xref: /freebsd/contrib/ntp/sntp/libevent/evdns.c (revision a466cc55373fc3cf86837f09da729535b57e69a1)
12b15cb3dSCy Schubert /* Copyright 2006-2007 Niels Provos
22b15cb3dSCy Schubert  * Copyright 2007-2012 Nick Mathewson and Niels Provos
32b15cb3dSCy Schubert  *
42b15cb3dSCy Schubert  * Redistribution and use in source and binary forms, with or without
52b15cb3dSCy Schubert  * modification, are permitted provided that the following conditions
62b15cb3dSCy Schubert  * are met:
72b15cb3dSCy Schubert  * 1. Redistributions of source code must retain the above copyright
82b15cb3dSCy Schubert  *    notice, this list of conditions and the following disclaimer.
92b15cb3dSCy Schubert  * 2. Redistributions in binary form must reproduce the above copyright
102b15cb3dSCy Schubert  *    notice, this list of conditions and the following disclaimer in the
112b15cb3dSCy Schubert  *    documentation and/or other materials provided with the distribution.
122b15cb3dSCy Schubert  * 3. The name of the author may not be used to endorse or promote products
132b15cb3dSCy Schubert  *    derived from this software without specific prior written permission.
142b15cb3dSCy Schubert  *
152b15cb3dSCy Schubert  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
162b15cb3dSCy Schubert  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
172b15cb3dSCy Schubert  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
182b15cb3dSCy Schubert  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
192b15cb3dSCy Schubert  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
202b15cb3dSCy Schubert  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
212b15cb3dSCy Schubert  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
222b15cb3dSCy Schubert  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
232b15cb3dSCy Schubert  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
242b15cb3dSCy Schubert  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
252b15cb3dSCy Schubert  */
262b15cb3dSCy Schubert 
272b15cb3dSCy Schubert /* Based on software by Adam Langly. Adam's original message:
282b15cb3dSCy Schubert  *
292b15cb3dSCy Schubert  * Async DNS Library
302b15cb3dSCy Schubert  * Adam Langley <agl@imperialviolet.org>
312b15cb3dSCy Schubert  * http://www.imperialviolet.org/eventdns.html
322b15cb3dSCy Schubert  * Public Domain code
332b15cb3dSCy Schubert  *
342b15cb3dSCy Schubert  * This software is Public Domain. To view a copy of the public domain dedication,
352b15cb3dSCy Schubert  * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
362b15cb3dSCy Schubert  * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
372b15cb3dSCy Schubert  *
382b15cb3dSCy Schubert  * I ask and expect, but do not require, that all derivative works contain an
392b15cb3dSCy Schubert  * attribution similar to:
402b15cb3dSCy Schubert  *	Parts developed by Adam Langley <agl@imperialviolet.org>
412b15cb3dSCy Schubert  *
422b15cb3dSCy Schubert  * You may wish to replace the word "Parts" with something else depending on
432b15cb3dSCy Schubert  * the amount of original code.
442b15cb3dSCy Schubert  *
452b15cb3dSCy Schubert  * (Derivative works does not include programs which link against, run or include
462b15cb3dSCy Schubert  * the source verbatim in their source distributions)
472b15cb3dSCy Schubert  *
482b15cb3dSCy Schubert  * Version: 0.1b
492b15cb3dSCy Schubert  */
502b15cb3dSCy Schubert 
512b15cb3dSCy Schubert #include "event2/event-config.h"
522b15cb3dSCy Schubert #include "evconfig-private.h"
532b15cb3dSCy Schubert 
542b15cb3dSCy Schubert #include <sys/types.h>
552b15cb3dSCy Schubert 
562b15cb3dSCy Schubert #ifndef _FORTIFY_SOURCE
572b15cb3dSCy Schubert #define _FORTIFY_SOURCE 3
582b15cb3dSCy Schubert #endif
592b15cb3dSCy Schubert 
602b15cb3dSCy Schubert #include <string.h>
612b15cb3dSCy Schubert #include <fcntl.h>
622b15cb3dSCy Schubert #ifdef EVENT__HAVE_SYS_TIME_H
632b15cb3dSCy Schubert #include <sys/time.h>
642b15cb3dSCy Schubert #endif
652b15cb3dSCy Schubert #ifdef EVENT__HAVE_STDINT_H
662b15cb3dSCy Schubert #include <stdint.h>
672b15cb3dSCy Schubert #endif
682b15cb3dSCy Schubert #include <stdlib.h>
692b15cb3dSCy Schubert #include <string.h>
702b15cb3dSCy Schubert #include <errno.h>
712b15cb3dSCy Schubert #ifdef EVENT__HAVE_UNISTD_H
722b15cb3dSCy Schubert #include <unistd.h>
732b15cb3dSCy Schubert #endif
742b15cb3dSCy Schubert #include <limits.h>
752b15cb3dSCy Schubert #include <sys/stat.h>
762b15cb3dSCy Schubert #include <stdio.h>
772b15cb3dSCy Schubert #include <stdarg.h>
782b15cb3dSCy Schubert #ifdef _WIN32
792b15cb3dSCy Schubert #include <winsock2.h>
80*a466cc55SCy Schubert #include <winerror.h>
812b15cb3dSCy Schubert #include <ws2tcpip.h>
822b15cb3dSCy Schubert #ifndef _WIN32_IE
832b15cb3dSCy Schubert #define _WIN32_IE 0x400
842b15cb3dSCy Schubert #endif
852b15cb3dSCy Schubert #include <shlobj.h>
862b15cb3dSCy Schubert #endif
872b15cb3dSCy Schubert 
882b15cb3dSCy Schubert #include "event2/dns.h"
892b15cb3dSCy Schubert #include "event2/dns_struct.h"
902b15cb3dSCy Schubert #include "event2/dns_compat.h"
912b15cb3dSCy Schubert #include "event2/util.h"
922b15cb3dSCy Schubert #include "event2/event.h"
932b15cb3dSCy Schubert #include "event2/event_struct.h"
942b15cb3dSCy Schubert #include "event2/thread.h"
952b15cb3dSCy Schubert 
962b15cb3dSCy Schubert #include "defer-internal.h"
972b15cb3dSCy Schubert #include "log-internal.h"
982b15cb3dSCy Schubert #include "mm-internal.h"
992b15cb3dSCy Schubert #include "strlcpy-internal.h"
1002b15cb3dSCy Schubert #include "ipv6-internal.h"
1012b15cb3dSCy Schubert #include "util-internal.h"
1022b15cb3dSCy Schubert #include "evthread-internal.h"
1032b15cb3dSCy Schubert #ifdef _WIN32
1042b15cb3dSCy Schubert #include <ctype.h>
1052b15cb3dSCy Schubert #include <winsock2.h>
1062b15cb3dSCy Schubert #include <windows.h>
1072b15cb3dSCy Schubert #include <iphlpapi.h>
1082b15cb3dSCy Schubert #include <io.h>
1092b15cb3dSCy Schubert #else
1102b15cb3dSCy Schubert #include <sys/socket.h>
1112b15cb3dSCy Schubert #include <netinet/in.h>
1122b15cb3dSCy Schubert #include <arpa/inet.h>
1132b15cb3dSCy Schubert #endif
1142b15cb3dSCy Schubert 
1152b15cb3dSCy Schubert #ifdef EVENT__HAVE_NETINET_IN6_H
1162b15cb3dSCy Schubert #include <netinet/in6.h>
1172b15cb3dSCy Schubert #endif
1182b15cb3dSCy Schubert 
1192b15cb3dSCy Schubert #define EVDNS_LOG_DEBUG EVENT_LOG_DEBUG
1202b15cb3dSCy Schubert #define EVDNS_LOG_WARN EVENT_LOG_WARN
1212b15cb3dSCy Schubert #define EVDNS_LOG_MSG EVENT_LOG_MSG
1222b15cb3dSCy Schubert 
1232b15cb3dSCy Schubert #ifndef HOST_NAME_MAX
1242b15cb3dSCy Schubert #define HOST_NAME_MAX 255
1252b15cb3dSCy Schubert #endif
1262b15cb3dSCy Schubert 
1272b15cb3dSCy Schubert #include <stdio.h>
1282b15cb3dSCy Schubert 
1292b15cb3dSCy Schubert #undef MIN
1302b15cb3dSCy Schubert #define MIN(a,b) ((a)<(b)?(a):(b))
1312b15cb3dSCy Schubert 
1322b15cb3dSCy Schubert #define ASSERT_VALID_REQUEST(req) \
1332b15cb3dSCy Schubert 	EVUTIL_ASSERT((req)->handle && (req)->handle->current_req == (req))
1342b15cb3dSCy Schubert 
1352b15cb3dSCy Schubert #define u64 ev_uint64_t
1362b15cb3dSCy Schubert #define u32 ev_uint32_t
1372b15cb3dSCy Schubert #define u16 ev_uint16_t
1382b15cb3dSCy Schubert #define u8  ev_uint8_t
1392b15cb3dSCy Schubert 
1402b15cb3dSCy Schubert /* maximum number of addresses from a single packet */
1412b15cb3dSCy Schubert /* that we bother recording */
1422b15cb3dSCy Schubert #define MAX_V4_ADDRS 32
1432b15cb3dSCy Schubert #define MAX_V6_ADDRS 32
1442b15cb3dSCy Schubert 
1452b15cb3dSCy Schubert 
1462b15cb3dSCy Schubert #define TYPE_A	       EVDNS_TYPE_A
1472b15cb3dSCy Schubert #define TYPE_CNAME     5
1482b15cb3dSCy Schubert #define TYPE_PTR       EVDNS_TYPE_PTR
1492b15cb3dSCy Schubert #define TYPE_SOA       EVDNS_TYPE_SOA
1502b15cb3dSCy Schubert #define TYPE_AAAA      EVDNS_TYPE_AAAA
1512b15cb3dSCy Schubert 
1522b15cb3dSCy Schubert #define CLASS_INET     EVDNS_CLASS_INET
1532b15cb3dSCy Schubert 
1542b15cb3dSCy Schubert /* Persistent handle.  We keep this separate from 'struct request' since we
1552b15cb3dSCy Schubert  * need some object to last for as long as an evdns_request is outstanding so
1562b15cb3dSCy Schubert  * that it can be canceled, whereas a search request can lead to multiple
1572b15cb3dSCy Schubert  * 'struct request' instances being created over its lifetime. */
1582b15cb3dSCy Schubert struct evdns_request {
1592b15cb3dSCy Schubert 	struct request *current_req;
1602b15cb3dSCy Schubert 	struct evdns_base *base;
1612b15cb3dSCy Schubert 
1622b15cb3dSCy Schubert 	int pending_cb; /* Waiting for its callback to be invoked; not
1632b15cb3dSCy Schubert 			 * owned by event base any more. */
1642b15cb3dSCy Schubert 
1652b15cb3dSCy Schubert 	/* elements used by the searching code */
1662b15cb3dSCy Schubert 	int search_index;
1672b15cb3dSCy Schubert 	struct search_state *search_state;
1682b15cb3dSCy Schubert 	char *search_origname;	/* needs to be free()ed */
1692b15cb3dSCy Schubert 	int search_flags;
1702b15cb3dSCy Schubert };
1712b15cb3dSCy Schubert 
1722b15cb3dSCy Schubert struct request {
1732b15cb3dSCy Schubert 	u8 *request;  /* the dns packet data */
1742b15cb3dSCy Schubert 	u8 request_type; /* TYPE_PTR or TYPE_A or TYPE_AAAA */
1752b15cb3dSCy Schubert 	unsigned int request_len;
1762b15cb3dSCy Schubert 	int reissue_count;
1772b15cb3dSCy Schubert 	int tx_count;  /* the number of times that this packet has been sent */
1782b15cb3dSCy Schubert 	void *user_pointer;  /* the pointer given to us for this request */
1792b15cb3dSCy Schubert 	evdns_callback_type user_callback;
1802b15cb3dSCy Schubert 	struct nameserver *ns;	/* the server which we last sent it */
1812b15cb3dSCy Schubert 
1822b15cb3dSCy Schubert 	/* these objects are kept in a circular list */
1832b15cb3dSCy Schubert 	/* XXX We could turn this into a CIRCLEQ. */
1842b15cb3dSCy Schubert 	struct request *next, *prev;
1852b15cb3dSCy Schubert 
1862b15cb3dSCy Schubert 	struct event timeout_event;
1872b15cb3dSCy Schubert 
1882b15cb3dSCy Schubert 	u16 trans_id;  /* the transaction id */
1892b15cb3dSCy Schubert 	unsigned request_appended :1;	/* true if the request pointer is data which follows this struct */
1902b15cb3dSCy Schubert 	unsigned transmit_me :1;  /* needs to be transmitted */
1912b15cb3dSCy Schubert 
1922b15cb3dSCy Schubert 	/* XXXX This is a horrible hack. */
1932b15cb3dSCy Schubert 	char **put_cname_in_ptr; /* store the cname here if we get one. */
1942b15cb3dSCy Schubert 
1952b15cb3dSCy Schubert 	struct evdns_base *base;
1962b15cb3dSCy Schubert 
1972b15cb3dSCy Schubert 	struct evdns_request *handle;
1982b15cb3dSCy Schubert };
1992b15cb3dSCy Schubert 
2002b15cb3dSCy Schubert struct reply {
2012b15cb3dSCy Schubert 	unsigned int type;
2022b15cb3dSCy Schubert 	unsigned int have_answer : 1;
2032b15cb3dSCy Schubert 	union {
2042b15cb3dSCy Schubert 		struct {
2052b15cb3dSCy Schubert 			u32 addrcount;
2062b15cb3dSCy Schubert 			u32 addresses[MAX_V4_ADDRS];
2072b15cb3dSCy Schubert 		} a;
2082b15cb3dSCy Schubert 		struct {
2092b15cb3dSCy Schubert 			u32 addrcount;
2102b15cb3dSCy Schubert 			struct in6_addr addresses[MAX_V6_ADDRS];
2112b15cb3dSCy Schubert 		} aaaa;
2122b15cb3dSCy Schubert 		struct {
2132b15cb3dSCy Schubert 			char name[HOST_NAME_MAX];
2142b15cb3dSCy Schubert 		} ptr;
2152b15cb3dSCy Schubert 	} data;
2162b15cb3dSCy Schubert };
2172b15cb3dSCy Schubert 
2182b15cb3dSCy Schubert struct nameserver {
2192b15cb3dSCy Schubert 	evutil_socket_t socket;	 /* a connected UDP socket */
2202b15cb3dSCy Schubert 	struct sockaddr_storage address;
2212b15cb3dSCy Schubert 	ev_socklen_t addrlen;
2222b15cb3dSCy Schubert 	int failed_times;  /* number of times which we have given this server a chance */
2232b15cb3dSCy Schubert 	int timedout;  /* number of times in a row a request has timed out */
2242b15cb3dSCy Schubert 	struct event event;
2252b15cb3dSCy Schubert 	/* these objects are kept in a circular list */
2262b15cb3dSCy Schubert 	struct nameserver *next, *prev;
2272b15cb3dSCy Schubert 	struct event timeout_event;  /* used to keep the timeout for */
2282b15cb3dSCy Schubert 				     /* when we next probe this server. */
2292b15cb3dSCy Schubert 				     /* Valid if state == 0 */
2302b15cb3dSCy Schubert 	/* Outstanding probe request for this nameserver, if any */
2312b15cb3dSCy Schubert 	struct evdns_request *probe_request;
2322b15cb3dSCy Schubert 	char state;  /* zero if we think that this server is down */
2332b15cb3dSCy Schubert 	char choked;  /* true if we have an EAGAIN from this server's socket */
2342b15cb3dSCy Schubert 	char write_waiting;  /* true if we are waiting for EV_WRITE events */
2352b15cb3dSCy Schubert 	struct evdns_base *base;
2362b15cb3dSCy Schubert 
2372b15cb3dSCy Schubert 	/* Number of currently inflight requests: used
2382b15cb3dSCy Schubert 	 * to track when we should add/del the event. */
2392b15cb3dSCy Schubert 	int requests_inflight;
2402b15cb3dSCy Schubert };
2412b15cb3dSCy Schubert 
2422b15cb3dSCy Schubert 
2432b15cb3dSCy Schubert /* Represents a local port where we're listening for DNS requests. Right now, */
2442b15cb3dSCy Schubert /* only UDP is supported. */
2452b15cb3dSCy Schubert struct evdns_server_port {
2462b15cb3dSCy Schubert 	evutil_socket_t socket; /* socket we use to read queries and write replies. */
2472b15cb3dSCy Schubert 	int refcnt; /* reference count. */
2482b15cb3dSCy Schubert 	char choked; /* Are we currently blocked from writing? */
2492b15cb3dSCy Schubert 	char closing; /* Are we trying to close this port, pending writes? */
2502b15cb3dSCy Schubert 	evdns_request_callback_fn_type user_callback; /* Fn to handle requests */
2512b15cb3dSCy Schubert 	void *user_data; /* Opaque pointer passed to user_callback */
2522b15cb3dSCy Schubert 	struct event event; /* Read/write event */
2532b15cb3dSCy Schubert 	/* circular list of replies that we want to write. */
2542b15cb3dSCy Schubert 	struct server_request *pending_replies;
2552b15cb3dSCy Schubert 	struct event_base *event_base;
2562b15cb3dSCy Schubert 
2572b15cb3dSCy Schubert #ifndef EVENT__DISABLE_THREAD_SUPPORT
2582b15cb3dSCy Schubert 	void *lock;
2592b15cb3dSCy Schubert #endif
2602b15cb3dSCy Schubert };
2612b15cb3dSCy Schubert 
2622b15cb3dSCy Schubert /* Represents part of a reply being built.	(That is, a single RR.) */
2632b15cb3dSCy Schubert struct server_reply_item {
2642b15cb3dSCy Schubert 	struct server_reply_item *next; /* next item in sequence. */
2652b15cb3dSCy Schubert 	char *name; /* name part of the RR */
2662b15cb3dSCy Schubert 	u16 type; /* The RR type */
2672b15cb3dSCy Schubert 	u16 class; /* The RR class (usually CLASS_INET) */
2682b15cb3dSCy Schubert 	u32 ttl; /* The RR TTL */
2692b15cb3dSCy Schubert 	char is_name; /* True iff data is a label */
2702b15cb3dSCy Schubert 	u16 datalen; /* Length of data; -1 if data is a label */
2712b15cb3dSCy Schubert 	void *data; /* The contents of the RR */
2722b15cb3dSCy Schubert };
2732b15cb3dSCy Schubert 
2742b15cb3dSCy Schubert /* Represents a request that we've received as a DNS server, and holds */
2752b15cb3dSCy Schubert /* the components of the reply as we're constructing it. */
2762b15cb3dSCy Schubert struct server_request {
2772b15cb3dSCy Schubert 	/* Pointers to the next and previous entries on the list of replies */
2782b15cb3dSCy Schubert 	/* that we're waiting to write.	 Only set if we have tried to respond */
2792b15cb3dSCy Schubert 	/* and gotten EAGAIN. */
2802b15cb3dSCy Schubert 	struct server_request *next_pending;
2812b15cb3dSCy Schubert 	struct server_request *prev_pending;
2822b15cb3dSCy Schubert 
2832b15cb3dSCy Schubert 	u16 trans_id; /* Transaction id. */
2842b15cb3dSCy Schubert 	struct evdns_server_port *port; /* Which port received this request on? */
2852b15cb3dSCy Schubert 	struct sockaddr_storage addr; /* Where to send the response */
2862b15cb3dSCy Schubert 	ev_socklen_t addrlen; /* length of addr */
2872b15cb3dSCy Schubert 
2882b15cb3dSCy Schubert 	int n_answer; /* how many answer RRs have been set? */
2892b15cb3dSCy Schubert 	int n_authority; /* how many authority RRs have been set? */
2902b15cb3dSCy Schubert 	int n_additional; /* how many additional RRs have been set? */
2912b15cb3dSCy Schubert 
2922b15cb3dSCy Schubert 	struct server_reply_item *answer; /* linked list of answer RRs */
2932b15cb3dSCy Schubert 	struct server_reply_item *authority; /* linked list of authority RRs */
2942b15cb3dSCy Schubert 	struct server_reply_item *additional; /* linked list of additional RRs */
2952b15cb3dSCy Schubert 
2962b15cb3dSCy Schubert 	/* Constructed response.  Only set once we're ready to send a reply. */
2972b15cb3dSCy Schubert 	/* Once this is set, the RR fields are cleared, and no more should be set. */
2982b15cb3dSCy Schubert 	char *response;
2992b15cb3dSCy Schubert 	size_t response_len;
3002b15cb3dSCy Schubert 
3012b15cb3dSCy Schubert 	/* Caller-visible fields: flags, questions. */
3022b15cb3dSCy Schubert 	struct evdns_server_request base;
3032b15cb3dSCy Schubert };
3042b15cb3dSCy Schubert 
3052b15cb3dSCy Schubert struct evdns_base {
3062b15cb3dSCy Schubert 	/* An array of n_req_heads circular lists for inflight requests.
3072b15cb3dSCy Schubert 	 * Each inflight request req is in req_heads[req->trans_id % n_req_heads].
3082b15cb3dSCy Schubert 	 */
3092b15cb3dSCy Schubert 	struct request **req_heads;
3102b15cb3dSCy Schubert 	/* A circular list of requests that we're waiting to send, but haven't
3112b15cb3dSCy Schubert 	 * sent yet because there are too many requests inflight */
3122b15cb3dSCy Schubert 	struct request *req_waiting_head;
3132b15cb3dSCy Schubert 	/* A circular list of nameservers. */
3142b15cb3dSCy Schubert 	struct nameserver *server_head;
3152b15cb3dSCy Schubert 	int n_req_heads;
3162b15cb3dSCy Schubert 
3172b15cb3dSCy Schubert 	struct event_base *event_base;
3182b15cb3dSCy Schubert 
3192b15cb3dSCy Schubert 	/* The number of good nameservers that we have */
3202b15cb3dSCy Schubert 	int global_good_nameservers;
3212b15cb3dSCy Schubert 
3222b15cb3dSCy Schubert 	/* inflight requests are contained in the req_head list */
3232b15cb3dSCy Schubert 	/* and are actually going out across the network */
3242b15cb3dSCy Schubert 	int global_requests_inflight;
3252b15cb3dSCy Schubert 	/* requests which aren't inflight are in the waiting list */
3262b15cb3dSCy Schubert 	/* and are counted here */
3272b15cb3dSCy Schubert 	int global_requests_waiting;
3282b15cb3dSCy Schubert 
3292b15cb3dSCy Schubert 	int global_max_requests_inflight;
3302b15cb3dSCy Schubert 
3312b15cb3dSCy Schubert 	struct timeval global_timeout;	/* 5 seconds by default */
3322b15cb3dSCy Schubert 	int global_max_reissues;  /* a reissue occurs when we get some errors from the server */
3332b15cb3dSCy Schubert 	int global_max_retransmits;  /* number of times we'll retransmit a request which timed out */
3342b15cb3dSCy Schubert 	/* number of timeouts in a row before we consider this server to be down */
3352b15cb3dSCy Schubert 	int global_max_nameserver_timeout;
3362b15cb3dSCy Schubert 	/* true iff we will use the 0x20 hack to prevent poisoning attacks. */
3372b15cb3dSCy Schubert 	int global_randomize_case;
3382b15cb3dSCy Schubert 
3392b15cb3dSCy Schubert 	/* The first time that a nameserver fails, how long do we wait before
3402b15cb3dSCy Schubert 	 * probing to see if it has returned?  */
3412b15cb3dSCy Schubert 	struct timeval global_nameserver_probe_initial_timeout;
3422b15cb3dSCy Schubert 
3432b15cb3dSCy Schubert 	/** Port to bind to for outgoing DNS packets. */
3442b15cb3dSCy Schubert 	struct sockaddr_storage global_outgoing_address;
3452b15cb3dSCy Schubert 	/** ev_socklen_t for global_outgoing_address. 0 if it isn't set. */
3462b15cb3dSCy Schubert 	ev_socklen_t global_outgoing_addrlen;
3472b15cb3dSCy Schubert 
3482b15cb3dSCy Schubert 	struct timeval global_getaddrinfo_allow_skew;
3492b15cb3dSCy Schubert 
350*a466cc55SCy Schubert 	int so_rcvbuf;
351*a466cc55SCy Schubert 	int so_sndbuf;
352*a466cc55SCy Schubert 
3532b15cb3dSCy Schubert 	int getaddrinfo_ipv4_timeouts;
3542b15cb3dSCy Schubert 	int getaddrinfo_ipv6_timeouts;
3552b15cb3dSCy Schubert 	int getaddrinfo_ipv4_answered;
3562b15cb3dSCy Schubert 	int getaddrinfo_ipv6_answered;
3572b15cb3dSCy Schubert 
3582b15cb3dSCy Schubert 	struct search_state *global_search_state;
3592b15cb3dSCy Schubert 
3602b15cb3dSCy Schubert 	TAILQ_HEAD(hosts_list, hosts_entry) hostsdb;
3612b15cb3dSCy Schubert 
3622b15cb3dSCy Schubert #ifndef EVENT__DISABLE_THREAD_SUPPORT
3632b15cb3dSCy Schubert 	void *lock;
3642b15cb3dSCy Schubert #endif
3652b15cb3dSCy Schubert 
3662b15cb3dSCy Schubert 	int disable_when_inactive;
3672b15cb3dSCy Schubert };
3682b15cb3dSCy Schubert 
3692b15cb3dSCy Schubert struct hosts_entry {
3702b15cb3dSCy Schubert 	TAILQ_ENTRY(hosts_entry) next;
3712b15cb3dSCy Schubert 	union {
3722b15cb3dSCy Schubert 		struct sockaddr sa;
3732b15cb3dSCy Schubert 		struct sockaddr_in sin;
3742b15cb3dSCy Schubert 		struct sockaddr_in6 sin6;
3752b15cb3dSCy Schubert 	} addr;
3762b15cb3dSCy Schubert 	int addrlen;
3772b15cb3dSCy Schubert 	char hostname[1];
3782b15cb3dSCy Schubert };
3792b15cb3dSCy Schubert 
3802b15cb3dSCy Schubert static struct evdns_base *current_base = NULL;
3812b15cb3dSCy Schubert 
3822b15cb3dSCy Schubert struct evdns_base *
evdns_get_global_base(void)3832b15cb3dSCy Schubert evdns_get_global_base(void)
3842b15cb3dSCy Schubert {
3852b15cb3dSCy Schubert 	return current_base;
3862b15cb3dSCy Schubert }
3872b15cb3dSCy Schubert 
3882b15cb3dSCy Schubert /* Given a pointer to an evdns_server_request, get the corresponding */
3892b15cb3dSCy Schubert /* server_request. */
3902b15cb3dSCy Schubert #define TO_SERVER_REQUEST(base_ptr)					\
3912b15cb3dSCy Schubert 	((struct server_request*)					\
3922b15cb3dSCy Schubert 	  (((char*)(base_ptr) - evutil_offsetof(struct server_request, base))))
3932b15cb3dSCy Schubert 
3942b15cb3dSCy Schubert #define REQ_HEAD(base, id) ((base)->req_heads[id % (base)->n_req_heads])
3952b15cb3dSCy Schubert 
3962b15cb3dSCy Schubert static struct nameserver *nameserver_pick(struct evdns_base *base);
3972b15cb3dSCy Schubert static void evdns_request_insert(struct request *req, struct request **head);
3982b15cb3dSCy Schubert static void evdns_request_remove(struct request *req, struct request **head);
3992b15cb3dSCy Schubert static void nameserver_ready_callback(evutil_socket_t fd, short events, void *arg);
4002b15cb3dSCy Schubert static int evdns_transmit(struct evdns_base *base);
4012b15cb3dSCy Schubert static int evdns_request_transmit(struct request *req);
4022b15cb3dSCy Schubert static void nameserver_send_probe(struct nameserver *const ns);
4032b15cb3dSCy Schubert static void search_request_finished(struct evdns_request *const);
4042b15cb3dSCy Schubert static int search_try_next(struct evdns_request *const req);
4052b15cb3dSCy Schubert static 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);
4062b15cb3dSCy Schubert static void evdns_requests_pump_waiting_queue(struct evdns_base *base);
4072b15cb3dSCy Schubert static u16 transaction_id_pick(struct evdns_base *base);
4082b15cb3dSCy Schubert static 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);
4092b15cb3dSCy Schubert static void request_submit(struct request *const req);
4102b15cb3dSCy Schubert 
4112b15cb3dSCy Schubert static int server_request_free(struct server_request *req);
4122b15cb3dSCy Schubert static void server_request_free_answers(struct server_request *req);
4132b15cb3dSCy Schubert static void server_port_free(struct evdns_server_port *port);
4142b15cb3dSCy Schubert static void server_port_ready_callback(evutil_socket_t fd, short events, void *arg);
4152b15cb3dSCy Schubert static int evdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags, const char *const filename);
4162b15cb3dSCy Schubert static int evdns_base_set_option_impl(struct evdns_base *base,
4172b15cb3dSCy Schubert     const char *option, const char *val, int flags);
4182b15cb3dSCy Schubert static void evdns_base_free_and_unlock(struct evdns_base *base, int fail_requests);
4192b15cb3dSCy Schubert static void evdns_request_timeout_callback(evutil_socket_t fd, short events, void *arg);
4202b15cb3dSCy Schubert 
4212b15cb3dSCy Schubert static int strtoint(const char *const str);
4222b15cb3dSCy Schubert 
4232b15cb3dSCy Schubert #ifdef EVENT__DISABLE_THREAD_SUPPORT
4242b15cb3dSCy Schubert #define EVDNS_LOCK(base)  EVUTIL_NIL_STMT_
4252b15cb3dSCy Schubert #define EVDNS_UNLOCK(base) EVUTIL_NIL_STMT_
4262b15cb3dSCy Schubert #define ASSERT_LOCKED(base) EVUTIL_NIL_STMT_
4272b15cb3dSCy Schubert #else
4282b15cb3dSCy Schubert #define EVDNS_LOCK(base)			\
4292b15cb3dSCy Schubert 	EVLOCK_LOCK((base)->lock, 0)
4302b15cb3dSCy Schubert #define EVDNS_UNLOCK(base)			\
4312b15cb3dSCy Schubert 	EVLOCK_UNLOCK((base)->lock, 0)
4322b15cb3dSCy Schubert #define ASSERT_LOCKED(base)			\
4332b15cb3dSCy Schubert 	EVLOCK_ASSERT_LOCKED((base)->lock)
4342b15cb3dSCy Schubert #endif
4352b15cb3dSCy Schubert 
4362b15cb3dSCy Schubert static evdns_debug_log_fn_type evdns_log_fn = NULL;
4372b15cb3dSCy Schubert 
4382b15cb3dSCy Schubert void
evdns_set_log_fn(evdns_debug_log_fn_type fn)4392b15cb3dSCy Schubert evdns_set_log_fn(evdns_debug_log_fn_type fn)
4402b15cb3dSCy Schubert {
4412b15cb3dSCy Schubert 	evdns_log_fn = fn;
4422b15cb3dSCy Schubert }
4432b15cb3dSCy Schubert 
4442b15cb3dSCy Schubert #ifdef __GNUC__
4452b15cb3dSCy Schubert #define EVDNS_LOG_CHECK	 __attribute__ ((format(printf, 2, 3)))
4462b15cb3dSCy Schubert #else
4472b15cb3dSCy Schubert #define EVDNS_LOG_CHECK
4482b15cb3dSCy Schubert #endif
4492b15cb3dSCy Schubert 
4502b15cb3dSCy Schubert static void evdns_log_(int severity, const char *fmt, ...) EVDNS_LOG_CHECK;
4512b15cb3dSCy Schubert static void
evdns_log_(int severity,const char * fmt,...)4522b15cb3dSCy Schubert evdns_log_(int severity, const char *fmt, ...)
4532b15cb3dSCy Schubert {
4542b15cb3dSCy Schubert 	va_list args;
4552b15cb3dSCy Schubert 	va_start(args,fmt);
4562b15cb3dSCy Schubert 	if (evdns_log_fn) {
4572b15cb3dSCy Schubert 		char buf[512];
4582b15cb3dSCy Schubert 		int is_warn = (severity == EVDNS_LOG_WARN);
4592b15cb3dSCy Schubert 		evutil_vsnprintf(buf, sizeof(buf), fmt, args);
4602b15cb3dSCy Schubert 		evdns_log_fn(is_warn, buf);
4612b15cb3dSCy Schubert 	} else {
4622b15cb3dSCy Schubert 		event_logv_(severity, NULL, fmt, args);
4632b15cb3dSCy Schubert 	}
4642b15cb3dSCy Schubert 	va_end(args);
4652b15cb3dSCy Schubert }
4662b15cb3dSCy Schubert 
4672b15cb3dSCy Schubert #define log evdns_log_
4682b15cb3dSCy Schubert 
4692b15cb3dSCy Schubert /* This walks the list of inflight requests to find the */
4702b15cb3dSCy Schubert /* one with a matching transaction id. Returns NULL on */
4712b15cb3dSCy Schubert /* failure */
4722b15cb3dSCy Schubert static struct request *
request_find_from_trans_id(struct evdns_base * base,u16 trans_id)4732b15cb3dSCy Schubert request_find_from_trans_id(struct evdns_base *base, u16 trans_id) {
4742b15cb3dSCy Schubert 	struct request *req = REQ_HEAD(base, trans_id);
4752b15cb3dSCy Schubert 	struct request *const started_at = req;
4762b15cb3dSCy Schubert 
4772b15cb3dSCy Schubert 	ASSERT_LOCKED(base);
4782b15cb3dSCy Schubert 
4792b15cb3dSCy Schubert 	if (req) {
4802b15cb3dSCy Schubert 		do {
4812b15cb3dSCy Schubert 			if (req->trans_id == trans_id) return req;
4822b15cb3dSCy Schubert 			req = req->next;
4832b15cb3dSCy Schubert 		} while (req != started_at);
4842b15cb3dSCy Schubert 	}
4852b15cb3dSCy Schubert 
4862b15cb3dSCy Schubert 	return NULL;
4872b15cb3dSCy Schubert }
4882b15cb3dSCy Schubert 
4892b15cb3dSCy Schubert /* a libevent callback function which is called when a nameserver */
4902b15cb3dSCy Schubert /* has gone down and we want to test if it has came back to life yet */
4912b15cb3dSCy Schubert static void
nameserver_prod_callback(evutil_socket_t fd,short events,void * arg)4922b15cb3dSCy Schubert nameserver_prod_callback(evutil_socket_t fd, short events, void *arg) {
4932b15cb3dSCy Schubert 	struct nameserver *const ns = (struct nameserver *) arg;
4942b15cb3dSCy Schubert 	(void)fd;
4952b15cb3dSCy Schubert 	(void)events;
4962b15cb3dSCy Schubert 
4972b15cb3dSCy Schubert 	EVDNS_LOCK(ns->base);
4982b15cb3dSCy Schubert 	nameserver_send_probe(ns);
4992b15cb3dSCy Schubert 	EVDNS_UNLOCK(ns->base);
5002b15cb3dSCy Schubert }
5012b15cb3dSCy Schubert 
5022b15cb3dSCy Schubert /* a libevent callback which is called when a nameserver probe (to see if */
5032b15cb3dSCy Schubert /* it has come back to life) times out. We increment the count of failed_times */
5042b15cb3dSCy Schubert /* and wait longer to send the next probe packet. */
5052b15cb3dSCy Schubert static void
nameserver_probe_failed(struct nameserver * const ns)5062b15cb3dSCy Schubert nameserver_probe_failed(struct nameserver *const ns) {
5072b15cb3dSCy Schubert 	struct timeval timeout;
5082b15cb3dSCy Schubert 	int i;
5092b15cb3dSCy Schubert 
5102b15cb3dSCy Schubert 	ASSERT_LOCKED(ns->base);
5112b15cb3dSCy Schubert 	(void) evtimer_del(&ns->timeout_event);
5122b15cb3dSCy Schubert 	if (ns->state == 1) {
5132b15cb3dSCy Schubert 		/* This can happen if the nameserver acts in a way which makes us mark */
5142b15cb3dSCy Schubert 		/* it as bad and then starts sending good replies. */
5152b15cb3dSCy Schubert 		return;
5162b15cb3dSCy Schubert 	}
5172b15cb3dSCy Schubert 
5182b15cb3dSCy Schubert #define MAX_PROBE_TIMEOUT 3600
5192b15cb3dSCy Schubert #define TIMEOUT_BACKOFF_FACTOR 3
5202b15cb3dSCy Schubert 
5212b15cb3dSCy Schubert 	memcpy(&timeout, &ns->base->global_nameserver_probe_initial_timeout,
5222b15cb3dSCy Schubert 	    sizeof(struct timeval));
5232b15cb3dSCy Schubert 	for (i=ns->failed_times; i > 0 && timeout.tv_sec < MAX_PROBE_TIMEOUT; --i) {
5242b15cb3dSCy Schubert 		timeout.tv_sec *= TIMEOUT_BACKOFF_FACTOR;
5252b15cb3dSCy Schubert 		timeout.tv_usec *= TIMEOUT_BACKOFF_FACTOR;
5262b15cb3dSCy Schubert 		if (timeout.tv_usec > 1000000) {
5272b15cb3dSCy Schubert 			timeout.tv_sec += timeout.tv_usec / 1000000;
5282b15cb3dSCy Schubert 			timeout.tv_usec %= 1000000;
5292b15cb3dSCy Schubert 		}
5302b15cb3dSCy Schubert 	}
5312b15cb3dSCy Schubert 	if (timeout.tv_sec > MAX_PROBE_TIMEOUT) {
5322b15cb3dSCy Schubert 		timeout.tv_sec = MAX_PROBE_TIMEOUT;
5332b15cb3dSCy Schubert 		timeout.tv_usec = 0;
5342b15cb3dSCy Schubert 	}
5352b15cb3dSCy Schubert 
5362b15cb3dSCy Schubert 	ns->failed_times++;
5372b15cb3dSCy Schubert 
5382b15cb3dSCy Schubert 	if (evtimer_add(&ns->timeout_event, &timeout) < 0) {
5392b15cb3dSCy Schubert 		char addrbuf[128];
5402b15cb3dSCy Schubert 		log(EVDNS_LOG_WARN,
5412b15cb3dSCy Schubert 		    "Error from libevent when adding timer event for %s",
5422b15cb3dSCy Schubert 		    evutil_format_sockaddr_port_(
5432b15cb3dSCy Schubert 			    (struct sockaddr *)&ns->address,
5442b15cb3dSCy Schubert 			    addrbuf, sizeof(addrbuf)));
5452b15cb3dSCy Schubert 	}
5462b15cb3dSCy Schubert }
5472b15cb3dSCy Schubert 
548a25439b6SCy Schubert static void
request_swap_ns(struct request * req,struct nameserver * ns)549a25439b6SCy Schubert request_swap_ns(struct request *req, struct nameserver *ns) {
550a25439b6SCy Schubert 	if (ns && req->ns != ns) {
551a25439b6SCy Schubert 		EVUTIL_ASSERT(req->ns->requests_inflight > 0);
552a25439b6SCy Schubert 		req->ns->requests_inflight--;
553a25439b6SCy Schubert 		ns->requests_inflight++;
554a25439b6SCy Schubert 
555a25439b6SCy Schubert 		req->ns = ns;
556a25439b6SCy Schubert 	}
557a25439b6SCy Schubert }
558a25439b6SCy Schubert 
5592b15cb3dSCy Schubert /* called when a nameserver has been deemed to have failed. For example, too */
5602b15cb3dSCy Schubert /* many packets have timed out etc */
5612b15cb3dSCy Schubert static void
nameserver_failed(struct nameserver * const ns,const char * msg)5622b15cb3dSCy Schubert nameserver_failed(struct nameserver *const ns, const char *msg) {
5632b15cb3dSCy Schubert 	struct request *req, *started_at;
5642b15cb3dSCy Schubert 	struct evdns_base *base = ns->base;
5652b15cb3dSCy Schubert 	int i;
5662b15cb3dSCy Schubert 	char addrbuf[128];
5672b15cb3dSCy Schubert 
5682b15cb3dSCy Schubert 	ASSERT_LOCKED(base);
5692b15cb3dSCy Schubert 	/* if this nameserver has already been marked as failed */
5702b15cb3dSCy Schubert 	/* then don't do anything */
5712b15cb3dSCy Schubert 	if (!ns->state) return;
5722b15cb3dSCy Schubert 
5732b15cb3dSCy Schubert 	log(EVDNS_LOG_MSG, "Nameserver %s has failed: %s",
5742b15cb3dSCy Schubert 	    evutil_format_sockaddr_port_(
5752b15cb3dSCy Schubert 		    (struct sockaddr *)&ns->address,
5762b15cb3dSCy Schubert 		    addrbuf, sizeof(addrbuf)),
5772b15cb3dSCy Schubert 	    msg);
5782b15cb3dSCy Schubert 
5792b15cb3dSCy Schubert 	base->global_good_nameservers--;
5802b15cb3dSCy Schubert 	EVUTIL_ASSERT(base->global_good_nameservers >= 0);
5812b15cb3dSCy Schubert 	if (base->global_good_nameservers == 0) {
5822b15cb3dSCy Schubert 		log(EVDNS_LOG_MSG, "All nameservers have failed");
5832b15cb3dSCy Schubert 	}
5842b15cb3dSCy Schubert 
5852b15cb3dSCy Schubert 	ns->state = 0;
5862b15cb3dSCy Schubert 	ns->failed_times = 1;
5872b15cb3dSCy Schubert 
5882b15cb3dSCy Schubert 	if (evtimer_add(&ns->timeout_event,
5892b15cb3dSCy Schubert 		&base->global_nameserver_probe_initial_timeout) < 0) {
5902b15cb3dSCy Schubert 		log(EVDNS_LOG_WARN,
5912b15cb3dSCy Schubert 		    "Error from libevent when adding timer event for %s",
5922b15cb3dSCy Schubert 		    evutil_format_sockaddr_port_(
5932b15cb3dSCy Schubert 			    (struct sockaddr *)&ns->address,
5942b15cb3dSCy Schubert 			    addrbuf, sizeof(addrbuf)));
5952b15cb3dSCy Schubert 		/* ???? Do more? */
5962b15cb3dSCy Schubert 	}
5972b15cb3dSCy Schubert 
5982b15cb3dSCy Schubert 	/* walk the list of inflight requests to see if any can be reassigned to */
5992b15cb3dSCy Schubert 	/* a different server. Requests in the waiting queue don't have a */
6002b15cb3dSCy Schubert 	/* nameserver assigned yet */
6012b15cb3dSCy Schubert 
6022b15cb3dSCy Schubert 	/* if we don't have *any* good nameservers then there's no point */
6032b15cb3dSCy Schubert 	/* trying to reassign requests to one */
6042b15cb3dSCy Schubert 	if (!base->global_good_nameservers) return;
6052b15cb3dSCy Schubert 
6062b15cb3dSCy Schubert 	for (i = 0; i < base->n_req_heads; ++i) {
6072b15cb3dSCy Schubert 		req = started_at = base->req_heads[i];
6082b15cb3dSCy Schubert 		if (req) {
6092b15cb3dSCy Schubert 			do {
6102b15cb3dSCy Schubert 				if (req->tx_count == 0 && req->ns == ns) {
6112b15cb3dSCy Schubert 					/* still waiting to go out, can be moved */
6122b15cb3dSCy Schubert 					/* to another server */
613a25439b6SCy Schubert 					request_swap_ns(req, nameserver_pick(base));
6142b15cb3dSCy Schubert 				}
6152b15cb3dSCy Schubert 				req = req->next;
6162b15cb3dSCy Schubert 			} while (req != started_at);
6172b15cb3dSCy Schubert 		}
6182b15cb3dSCy Schubert 	}
6192b15cb3dSCy Schubert }
6202b15cb3dSCy Schubert 
6212b15cb3dSCy Schubert static void
nameserver_up(struct nameserver * const ns)6222b15cb3dSCy Schubert nameserver_up(struct nameserver *const ns)
6232b15cb3dSCy Schubert {
6242b15cb3dSCy Schubert 	char addrbuf[128];
6252b15cb3dSCy Schubert 	ASSERT_LOCKED(ns->base);
6262b15cb3dSCy Schubert 	if (ns->state) return;
6272b15cb3dSCy Schubert 	log(EVDNS_LOG_MSG, "Nameserver %s is back up",
6282b15cb3dSCy Schubert 	    evutil_format_sockaddr_port_(
6292b15cb3dSCy Schubert 		    (struct sockaddr *)&ns->address,
6302b15cb3dSCy Schubert 		    addrbuf, sizeof(addrbuf)));
6312b15cb3dSCy Schubert 	evtimer_del(&ns->timeout_event);
6322b15cb3dSCy Schubert 	if (ns->probe_request) {
6332b15cb3dSCy Schubert 		evdns_cancel_request(ns->base, ns->probe_request);
6342b15cb3dSCy Schubert 		ns->probe_request = NULL;
6352b15cb3dSCy Schubert 	}
6362b15cb3dSCy Schubert 	ns->state = 1;
6372b15cb3dSCy Schubert 	ns->failed_times = 0;
6382b15cb3dSCy Schubert 	ns->timedout = 0;
6392b15cb3dSCy Schubert 	ns->base->global_good_nameservers++;
6402b15cb3dSCy Schubert }
6412b15cb3dSCy Schubert 
6422b15cb3dSCy Schubert static void
request_trans_id_set(struct request * const req,const u16 trans_id)6432b15cb3dSCy Schubert request_trans_id_set(struct request *const req, const u16 trans_id) {
6442b15cb3dSCy Schubert 	req->trans_id = trans_id;
6452b15cb3dSCy Schubert 	*((u16 *) req->request) = htons(trans_id);
6462b15cb3dSCy Schubert }
6472b15cb3dSCy Schubert 
6482b15cb3dSCy Schubert /* Called to remove a request from a list and dealloc it. */
6492b15cb3dSCy Schubert /* head is a pointer to the head of the list it should be */
6502b15cb3dSCy Schubert /* removed from or NULL if the request isn't in a list. */
6512b15cb3dSCy Schubert /* when free_handle is one, free the handle as well. */
6522b15cb3dSCy Schubert static void
request_finished(struct request * const req,struct request ** head,int free_handle)6532b15cb3dSCy Schubert request_finished(struct request *const req, struct request **head, int free_handle) {
6542b15cb3dSCy Schubert 	struct evdns_base *base = req->base;
6552b15cb3dSCy Schubert 	int was_inflight = (head != &base->req_waiting_head);
6562b15cb3dSCy Schubert 	EVDNS_LOCK(base);
6572b15cb3dSCy Schubert 	ASSERT_VALID_REQUEST(req);
6582b15cb3dSCy Schubert 
6592b15cb3dSCy Schubert 	if (head)
6602b15cb3dSCy Schubert 		evdns_request_remove(req, head);
6612b15cb3dSCy Schubert 
6622b15cb3dSCy Schubert 	log(EVDNS_LOG_DEBUG, "Removing timeout for request %p", req);
6632b15cb3dSCy Schubert 	if (was_inflight) {
6642b15cb3dSCy Schubert 		evtimer_del(&req->timeout_event);
6652b15cb3dSCy Schubert 		base->global_requests_inflight--;
6662b15cb3dSCy Schubert 		req->ns->requests_inflight--;
6672b15cb3dSCy Schubert 	} else {
6682b15cb3dSCy Schubert 		base->global_requests_waiting--;
6692b15cb3dSCy Schubert 	}
6702b15cb3dSCy Schubert 	/* it was initialized during request_new / evtimer_assign */
6712b15cb3dSCy Schubert 	event_debug_unassign(&req->timeout_event);
6722b15cb3dSCy Schubert 
6732b15cb3dSCy Schubert 	if (req->ns &&
6742b15cb3dSCy Schubert 	    req->ns->requests_inflight == 0 &&
6752b15cb3dSCy Schubert 	    req->base->disable_when_inactive) {
6762b15cb3dSCy Schubert 		event_del(&req->ns->event);
677a25439b6SCy Schubert 		evtimer_del(&req->ns->timeout_event);
6782b15cb3dSCy Schubert 	}
6792b15cb3dSCy Schubert 
6802b15cb3dSCy Schubert 	if (!req->request_appended) {
6812b15cb3dSCy Schubert 		/* need to free the request data on it's own */
6822b15cb3dSCy Schubert 		mm_free(req->request);
6832b15cb3dSCy Schubert 	} else {
6842b15cb3dSCy Schubert 		/* the request data is appended onto the header */
6852b15cb3dSCy Schubert 		/* so everything gets free()ed when we: */
6862b15cb3dSCy Schubert 	}
6872b15cb3dSCy Schubert 
6882b15cb3dSCy Schubert 	if (req->handle) {
6892b15cb3dSCy Schubert 		EVUTIL_ASSERT(req->handle->current_req == req);
6902b15cb3dSCy Schubert 
6912b15cb3dSCy Schubert 		if (free_handle) {
6922b15cb3dSCy Schubert 			search_request_finished(req->handle);
6932b15cb3dSCy Schubert 			req->handle->current_req = NULL;
6942b15cb3dSCy Schubert 			if (! req->handle->pending_cb) {
6952b15cb3dSCy Schubert 				/* If we're planning to run the callback,
6962b15cb3dSCy Schubert 				 * don't free the handle until later. */
6972b15cb3dSCy Schubert 				mm_free(req->handle);
6982b15cb3dSCy Schubert 			}
6992b15cb3dSCy Schubert 			req->handle = NULL; /* If we have a bug, let's crash
7002b15cb3dSCy Schubert 					     * early */
7012b15cb3dSCy Schubert 		} else {
7022b15cb3dSCy Schubert 			req->handle->current_req = NULL;
7032b15cb3dSCy Schubert 		}
7042b15cb3dSCy Schubert 	}
7052b15cb3dSCy Schubert 
7062b15cb3dSCy Schubert 	mm_free(req);
7072b15cb3dSCy Schubert 
7082b15cb3dSCy Schubert 	evdns_requests_pump_waiting_queue(base);
7092b15cb3dSCy Schubert 	EVDNS_UNLOCK(base);
7102b15cb3dSCy Schubert }
7112b15cb3dSCy Schubert 
7122b15cb3dSCy Schubert /* This is called when a server returns a funny error code. */
7132b15cb3dSCy Schubert /* We try the request again with another server. */
7142b15cb3dSCy Schubert /* */
7152b15cb3dSCy Schubert /* return: */
7162b15cb3dSCy Schubert /*   0 ok */
7172b15cb3dSCy Schubert /*   1 failed/reissue is pointless */
7182b15cb3dSCy Schubert static int
request_reissue(struct request * req)7192b15cb3dSCy Schubert request_reissue(struct request *req) {
7202b15cb3dSCy Schubert 	const struct nameserver *const last_ns = req->ns;
7212b15cb3dSCy Schubert 	ASSERT_LOCKED(req->base);
7222b15cb3dSCy Schubert 	ASSERT_VALID_REQUEST(req);
7232b15cb3dSCy Schubert 	/* the last nameserver should have been marked as failing */
7242b15cb3dSCy Schubert 	/* by the caller of this function, therefore pick will try */
7252b15cb3dSCy Schubert 	/* not to return it */
726a25439b6SCy Schubert 	request_swap_ns(req, nameserver_pick(req->base));
7272b15cb3dSCy Schubert 	if (req->ns == last_ns) {
7282b15cb3dSCy Schubert 		/* ... but pick did return it */
7292b15cb3dSCy Schubert 		/* not a lot of point in trying again with the */
7302b15cb3dSCy Schubert 		/* same server */
7312b15cb3dSCy Schubert 		return 1;
7322b15cb3dSCy Schubert 	}
7332b15cb3dSCy Schubert 
7342b15cb3dSCy Schubert 	req->reissue_count++;
7352b15cb3dSCy Schubert 	req->tx_count = 0;
7362b15cb3dSCy Schubert 	req->transmit_me = 1;
7372b15cb3dSCy Schubert 
7382b15cb3dSCy Schubert 	return 0;
7392b15cb3dSCy Schubert }
7402b15cb3dSCy Schubert 
7412b15cb3dSCy Schubert /* this function looks for space on the inflight queue and promotes */
7422b15cb3dSCy Schubert /* requests from the waiting queue if it can. */
7432b15cb3dSCy Schubert /* */
7442b15cb3dSCy Schubert /* TODO: */
7452b15cb3dSCy Schubert /* add return code, see at nameserver_pick() and other functions. */
7462b15cb3dSCy Schubert static void
evdns_requests_pump_waiting_queue(struct evdns_base * base)7472b15cb3dSCy Schubert evdns_requests_pump_waiting_queue(struct evdns_base *base) {
7482b15cb3dSCy Schubert 	ASSERT_LOCKED(base);
7492b15cb3dSCy Schubert 	while (base->global_requests_inflight < base->global_max_requests_inflight &&
7502b15cb3dSCy Schubert 		   base->global_requests_waiting) {
7512b15cb3dSCy Schubert 		struct request *req;
7522b15cb3dSCy Schubert 
7532b15cb3dSCy Schubert 		EVUTIL_ASSERT(base->req_waiting_head);
7542b15cb3dSCy Schubert 		req = base->req_waiting_head;
7552b15cb3dSCy Schubert 
7562b15cb3dSCy Schubert 		req->ns = nameserver_pick(base);
7572b15cb3dSCy Schubert 		if (!req->ns)
7582b15cb3dSCy Schubert 			return;
7592b15cb3dSCy Schubert 
7602b15cb3dSCy Schubert 		/* move a request from the waiting queue to the inflight queue */
7612b15cb3dSCy Schubert 		req->ns->requests_inflight++;
7622b15cb3dSCy Schubert 
7632b15cb3dSCy Schubert 		evdns_request_remove(req, &base->req_waiting_head);
7642b15cb3dSCy Schubert 
7652b15cb3dSCy Schubert 		base->global_requests_waiting--;
7662b15cb3dSCy Schubert 		base->global_requests_inflight++;
7672b15cb3dSCy Schubert 
7682b15cb3dSCy Schubert 		request_trans_id_set(req, transaction_id_pick(base));
7692b15cb3dSCy Schubert 
7702b15cb3dSCy Schubert 		evdns_request_insert(req, &REQ_HEAD(base, req->trans_id));
7712b15cb3dSCy Schubert 		evdns_request_transmit(req);
7722b15cb3dSCy Schubert 		evdns_transmit(base);
7732b15cb3dSCy Schubert 	}
7742b15cb3dSCy Schubert }
7752b15cb3dSCy Schubert 
7762b15cb3dSCy Schubert /* TODO(nickm) document */
7772b15cb3dSCy Schubert struct deferred_reply_callback {
7782b15cb3dSCy Schubert 	struct event_callback deferred;
7792b15cb3dSCy Schubert 	struct evdns_request *handle;
7802b15cb3dSCy Schubert 	u8 request_type;
7812b15cb3dSCy Schubert 	u8 have_reply;
7822b15cb3dSCy Schubert 	u32 ttl;
7832b15cb3dSCy Schubert 	u32 err;
7842b15cb3dSCy Schubert 	evdns_callback_type user_callback;
7852b15cb3dSCy Schubert 	struct reply reply;
7862b15cb3dSCy Schubert };
7872b15cb3dSCy Schubert 
7882b15cb3dSCy Schubert static void
reply_run_callback(struct event_callback * d,void * user_pointer)7892b15cb3dSCy Schubert reply_run_callback(struct event_callback *d, void *user_pointer)
7902b15cb3dSCy Schubert {
7912b15cb3dSCy Schubert 	struct deferred_reply_callback *cb =
7922b15cb3dSCy Schubert 	    EVUTIL_UPCAST(d, struct deferred_reply_callback, deferred);
7932b15cb3dSCy Schubert 
7942b15cb3dSCy Schubert 	switch (cb->request_type) {
7952b15cb3dSCy Schubert 	case TYPE_A:
7962b15cb3dSCy Schubert 		if (cb->have_reply)
7972b15cb3dSCy Schubert 			cb->user_callback(DNS_ERR_NONE, DNS_IPv4_A,
7982b15cb3dSCy Schubert 			    cb->reply.data.a.addrcount, cb->ttl,
7992b15cb3dSCy Schubert 			    cb->reply.data.a.addresses,
8002b15cb3dSCy Schubert 			    user_pointer);
8012b15cb3dSCy Schubert 		else
8022b15cb3dSCy Schubert 			cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer);
8032b15cb3dSCy Schubert 		break;
8042b15cb3dSCy Schubert 	case TYPE_PTR:
8052b15cb3dSCy Schubert 		if (cb->have_reply) {
8062b15cb3dSCy Schubert 			char *name = cb->reply.data.ptr.name;
8072b15cb3dSCy Schubert 			cb->user_callback(DNS_ERR_NONE, DNS_PTR, 1, cb->ttl,
8082b15cb3dSCy Schubert 			    &name, user_pointer);
8092b15cb3dSCy Schubert 		} else {
8102b15cb3dSCy Schubert 			cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer);
8112b15cb3dSCy Schubert 		}
8122b15cb3dSCy Schubert 		break;
8132b15cb3dSCy Schubert 	case TYPE_AAAA:
8142b15cb3dSCy Schubert 		if (cb->have_reply)
8152b15cb3dSCy Schubert 			cb->user_callback(DNS_ERR_NONE, DNS_IPv6_AAAA,
8162b15cb3dSCy Schubert 			    cb->reply.data.aaaa.addrcount, cb->ttl,
8172b15cb3dSCy Schubert 			    cb->reply.data.aaaa.addresses,
8182b15cb3dSCy Schubert 			    user_pointer);
8192b15cb3dSCy Schubert 		else
8202b15cb3dSCy Schubert 			cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer);
8212b15cb3dSCy Schubert 		break;
8222b15cb3dSCy Schubert 	default:
8232b15cb3dSCy Schubert 		EVUTIL_ASSERT(0);
8242b15cb3dSCy Schubert 	}
8252b15cb3dSCy Schubert 
8262b15cb3dSCy Schubert 	if (cb->handle && cb->handle->pending_cb) {
8272b15cb3dSCy Schubert 		mm_free(cb->handle);
8282b15cb3dSCy Schubert 	}
8292b15cb3dSCy Schubert 
8302b15cb3dSCy Schubert 	mm_free(cb);
8312b15cb3dSCy Schubert }
8322b15cb3dSCy Schubert 
8332b15cb3dSCy Schubert static void
reply_schedule_callback(struct request * const req,u32 ttl,u32 err,struct reply * reply)8342b15cb3dSCy Schubert reply_schedule_callback(struct request *const req, u32 ttl, u32 err, struct reply *reply)
8352b15cb3dSCy Schubert {
8362b15cb3dSCy Schubert 	struct deferred_reply_callback *d = mm_calloc(1, sizeof(*d));
8372b15cb3dSCy Schubert 
8382b15cb3dSCy Schubert 	if (!d) {
8392b15cb3dSCy Schubert 		event_warn("%s: Couldn't allocate space for deferred callback.",
8402b15cb3dSCy Schubert 		    __func__);
8412b15cb3dSCy Schubert 		return;
8422b15cb3dSCy Schubert 	}
8432b15cb3dSCy Schubert 
8442b15cb3dSCy Schubert 	ASSERT_LOCKED(req->base);
8452b15cb3dSCy Schubert 
8462b15cb3dSCy Schubert 	d->request_type = req->request_type;
8472b15cb3dSCy Schubert 	d->user_callback = req->user_callback;
8482b15cb3dSCy Schubert 	d->ttl = ttl;
8492b15cb3dSCy Schubert 	d->err = err;
8502b15cb3dSCy Schubert 	if (reply) {
8512b15cb3dSCy Schubert 		d->have_reply = 1;
8522b15cb3dSCy Schubert 		memcpy(&d->reply, reply, sizeof(struct reply));
8532b15cb3dSCy Schubert 	}
8542b15cb3dSCy Schubert 
8552b15cb3dSCy Schubert 	if (req->handle) {
8562b15cb3dSCy Schubert 		req->handle->pending_cb = 1;
8572b15cb3dSCy Schubert 		d->handle = req->handle;
8582b15cb3dSCy Schubert 	}
8592b15cb3dSCy Schubert 
8602b15cb3dSCy Schubert 	event_deferred_cb_init_(
8612b15cb3dSCy Schubert 	    &d->deferred,
8622b15cb3dSCy Schubert 	    event_get_priority(&req->timeout_event),
8632b15cb3dSCy Schubert 	    reply_run_callback,
8642b15cb3dSCy Schubert 	    req->user_pointer);
8652b15cb3dSCy Schubert 	event_deferred_cb_schedule_(
8662b15cb3dSCy Schubert 		req->base->event_base,
8672b15cb3dSCy Schubert 		&d->deferred);
8682b15cb3dSCy Schubert }
8692b15cb3dSCy Schubert 
870*a466cc55SCy Schubert 
871*a466cc55SCy Schubert #define _QR_MASK    0x8000U
872*a466cc55SCy Schubert #define _OP_MASK    0x7800U
873*a466cc55SCy Schubert #define _AA_MASK    0x0400U
874*a466cc55SCy Schubert #define _TC_MASK    0x0200U
875*a466cc55SCy Schubert #define _RD_MASK    0x0100U
876*a466cc55SCy Schubert #define _RA_MASK    0x0080U
877*a466cc55SCy Schubert #define _Z_MASK     0x0040U
878*a466cc55SCy Schubert #define _AD_MASK    0x0020U
879*a466cc55SCy Schubert #define _CD_MASK    0x0010U
880*a466cc55SCy Schubert #define _RCODE_MASK 0x000fU
881*a466cc55SCy Schubert #define _Z_MASK_DEPRECATED 0x0070U
882*a466cc55SCy Schubert 
8832b15cb3dSCy Schubert /* this processes a parsed reply packet */
8842b15cb3dSCy Schubert static void
reply_handle(struct request * const req,u16 flags,u32 ttl,struct reply * reply)8852b15cb3dSCy Schubert reply_handle(struct request *const req, u16 flags, u32 ttl, struct reply *reply) {
8862b15cb3dSCy Schubert 	int error;
8872b15cb3dSCy Schubert 	char addrbuf[128];
8882b15cb3dSCy Schubert 	static const int error_codes[] = {
8892b15cb3dSCy Schubert 		DNS_ERR_FORMAT, DNS_ERR_SERVERFAILED, DNS_ERR_NOTEXIST,
8902b15cb3dSCy Schubert 		DNS_ERR_NOTIMPL, DNS_ERR_REFUSED
8912b15cb3dSCy Schubert 	};
8922b15cb3dSCy Schubert 
8932b15cb3dSCy Schubert 	ASSERT_LOCKED(req->base);
8942b15cb3dSCy Schubert 	ASSERT_VALID_REQUEST(req);
8952b15cb3dSCy Schubert 
896*a466cc55SCy Schubert 	if (flags & (_RCODE_MASK | _TC_MASK) || !reply || !reply->have_answer) {
8972b15cb3dSCy Schubert 		/* there was an error */
898*a466cc55SCy Schubert 		if (flags & _TC_MASK) {
8992b15cb3dSCy Schubert 			error = DNS_ERR_TRUNCATED;
900*a466cc55SCy Schubert 		} else if (flags & _RCODE_MASK) {
901*a466cc55SCy Schubert 			u16 error_code = (flags & _RCODE_MASK) - 1;
9022b15cb3dSCy Schubert 			if (error_code > 4) {
9032b15cb3dSCy Schubert 				error = DNS_ERR_UNKNOWN;
9042b15cb3dSCy Schubert 			} else {
9052b15cb3dSCy Schubert 				error = error_codes[error_code];
9062b15cb3dSCy Schubert 			}
9072b15cb3dSCy Schubert 		} else if (reply && !reply->have_answer) {
9082b15cb3dSCy Schubert 			error = DNS_ERR_NODATA;
9092b15cb3dSCy Schubert 		} else {
9102b15cb3dSCy Schubert 			error = DNS_ERR_UNKNOWN;
9112b15cb3dSCy Schubert 		}
9122b15cb3dSCy Schubert 
9132b15cb3dSCy Schubert 		switch (error) {
9142b15cb3dSCy Schubert 		case DNS_ERR_NOTIMPL:
9152b15cb3dSCy Schubert 		case DNS_ERR_REFUSED:
9162b15cb3dSCy Schubert 			/* we regard these errors as marking a bad nameserver */
9172b15cb3dSCy Schubert 			if (req->reissue_count < req->base->global_max_reissues) {
9182b15cb3dSCy Schubert 				char msg[64];
9192b15cb3dSCy Schubert 				evutil_snprintf(msg, sizeof(msg), "Bad response %d (%s)",
9202b15cb3dSCy Schubert 					 error, evdns_err_to_string(error));
9212b15cb3dSCy Schubert 				nameserver_failed(req->ns, msg);
9222b15cb3dSCy Schubert 				if (!request_reissue(req)) return;
9232b15cb3dSCy Schubert 			}
9242b15cb3dSCy Schubert 			break;
9252b15cb3dSCy Schubert 		case DNS_ERR_SERVERFAILED:
9262b15cb3dSCy Schubert 			/* rcode 2 (servfailed) sometimes means "we
9272b15cb3dSCy Schubert 			 * are broken" and sometimes (with some binds)
9282b15cb3dSCy Schubert 			 * means "that request was very confusing."
9292b15cb3dSCy Schubert 			 * Treat this as a timeout, not a failure.
9302b15cb3dSCy Schubert 			 */
9312b15cb3dSCy Schubert 			log(EVDNS_LOG_DEBUG, "Got a SERVERFAILED from nameserver"
9322b15cb3dSCy Schubert 				"at %s; will allow the request to time out.",
9332b15cb3dSCy Schubert 			    evutil_format_sockaddr_port_(
9342b15cb3dSCy Schubert 				    (struct sockaddr *)&req->ns->address,
9352b15cb3dSCy Schubert 				    addrbuf, sizeof(addrbuf)));
9362b15cb3dSCy Schubert 			/* Call the timeout function */
9372b15cb3dSCy Schubert 			evdns_request_timeout_callback(0, 0, req);
9382b15cb3dSCy Schubert 			return;
9392b15cb3dSCy Schubert 		default:
9402b15cb3dSCy Schubert 			/* we got a good reply from the nameserver: it is up. */
9412b15cb3dSCy Schubert 			if (req->handle == req->ns->probe_request) {
9422b15cb3dSCy Schubert 				/* Avoid double-free */
9432b15cb3dSCy Schubert 				req->ns->probe_request = NULL;
9442b15cb3dSCy Schubert 			}
9452b15cb3dSCy Schubert 
9462b15cb3dSCy Schubert 			nameserver_up(req->ns);
9472b15cb3dSCy Schubert 		}
9482b15cb3dSCy Schubert 
9492b15cb3dSCy Schubert 		if (req->handle->search_state &&
9502b15cb3dSCy Schubert 		    req->request_type != TYPE_PTR) {
9512b15cb3dSCy Schubert 			/* if we have a list of domains to search in,
9522b15cb3dSCy Schubert 			 * try the next one */
9532b15cb3dSCy Schubert 			if (!search_try_next(req->handle)) {
9542b15cb3dSCy Schubert 				/* a new request was issued so this
9552b15cb3dSCy Schubert 				 * request is finished and */
9562b15cb3dSCy Schubert 				/* the user callback will be made when
9572b15cb3dSCy Schubert 				 * that request (or a */
9582b15cb3dSCy Schubert 				/* child of it) finishes. */
9592b15cb3dSCy Schubert 				return;
9602b15cb3dSCy Schubert 			}
9612b15cb3dSCy Schubert 		}
9622b15cb3dSCy Schubert 
9632b15cb3dSCy Schubert 		/* all else failed. Pass the failure up */
9642b15cb3dSCy Schubert 		reply_schedule_callback(req, ttl, error, NULL);
9652b15cb3dSCy Schubert 		request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1);
9662b15cb3dSCy Schubert 	} else {
9672b15cb3dSCy Schubert 		/* all ok, tell the user */
9682b15cb3dSCy Schubert 		reply_schedule_callback(req, ttl, 0, reply);
9692b15cb3dSCy Schubert 		if (req->handle == req->ns->probe_request)
9702b15cb3dSCy Schubert 			req->ns->probe_request = NULL; /* Avoid double-free */
9712b15cb3dSCy Schubert 		nameserver_up(req->ns);
9722b15cb3dSCy Schubert 		request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1);
9732b15cb3dSCy Schubert 	}
9742b15cb3dSCy Schubert }
9752b15cb3dSCy Schubert 
9762b15cb3dSCy Schubert static int
name_parse(u8 * packet,int length,int * idx,char * name_out,int name_out_len)9772b15cb3dSCy Schubert name_parse(u8 *packet, int length, int *idx, char *name_out, int name_out_len) {
9782b15cb3dSCy Schubert 	int name_end = -1;
9792b15cb3dSCy Schubert 	int j = *idx;
9802b15cb3dSCy Schubert 	int ptr_count = 0;
9812b15cb3dSCy Schubert #define GET32(x) do { if (j + 4 > length) goto err; memcpy(&t32_, packet + j, 4); j += 4; x = ntohl(t32_); } while (0)
9822b15cb3dSCy Schubert #define GET16(x) do { if (j + 2 > length) goto err; memcpy(&t_, packet + j, 2); j += 2; x = ntohs(t_); } while (0)
9832b15cb3dSCy Schubert #define GET8(x) do { if (j >= length) goto err; x = packet[j++]; } while (0)
9842b15cb3dSCy Schubert 
9852b15cb3dSCy Schubert 	char *cp = name_out;
9862b15cb3dSCy Schubert 	const char *const end = name_out + name_out_len;
9872b15cb3dSCy Schubert 
9882b15cb3dSCy Schubert 	/* Normally, names are a series of length prefixed strings terminated */
9892b15cb3dSCy Schubert 	/* with a length of 0 (the lengths are u8's < 63). */
9902b15cb3dSCy Schubert 	/* However, the length can start with a pair of 1 bits and that */
9912b15cb3dSCy Schubert 	/* means that the next 14 bits are a pointer within the current */
9922b15cb3dSCy Schubert 	/* packet. */
9932b15cb3dSCy Schubert 
9942b15cb3dSCy Schubert 	for (;;) {
9952b15cb3dSCy Schubert 		u8 label_len;
9962b15cb3dSCy Schubert 		GET8(label_len);
9972b15cb3dSCy Schubert 		if (!label_len) break;
9982b15cb3dSCy Schubert 		if (label_len & 0xc0) {
9992b15cb3dSCy Schubert 			u8 ptr_low;
10002b15cb3dSCy Schubert 			GET8(ptr_low);
10012b15cb3dSCy Schubert 			if (name_end < 0) name_end = j;
10022b15cb3dSCy Schubert 			j = (((int)label_len & 0x3f) << 8) + ptr_low;
10032b15cb3dSCy Schubert 			/* Make sure that the target offset is in-bounds. */
10042b15cb3dSCy Schubert 			if (j < 0 || j >= length) return -1;
10052b15cb3dSCy Schubert 			/* If we've jumped more times than there are characters in the
10062b15cb3dSCy Schubert 			 * message, we must have a loop. */
10072b15cb3dSCy Schubert 			if (++ptr_count > length) return -1;
10082b15cb3dSCy Schubert 			continue;
10092b15cb3dSCy Schubert 		}
10102b15cb3dSCy Schubert 		if (label_len > 63) return -1;
10112b15cb3dSCy Schubert 		if (cp != name_out) {
10122b15cb3dSCy Schubert 			if (cp + 1 >= end) return -1;
10132b15cb3dSCy Schubert 			*cp++ = '.';
10142b15cb3dSCy Schubert 		}
10152b15cb3dSCy Schubert 		if (cp + label_len >= end) return -1;
1016*a466cc55SCy Schubert 		if (j + label_len > length) return -1;
10172b15cb3dSCy Schubert 		memcpy(cp, packet + j, label_len);
10182b15cb3dSCy Schubert 		cp += label_len;
10192b15cb3dSCy Schubert 		j += label_len;
10202b15cb3dSCy Schubert 	}
10212b15cb3dSCy Schubert 	if (cp >= end) return -1;
10222b15cb3dSCy Schubert 	*cp = '\0';
10232b15cb3dSCy Schubert 	if (name_end < 0)
10242b15cb3dSCy Schubert 		*idx = j;
10252b15cb3dSCy Schubert 	else
10262b15cb3dSCy Schubert 		*idx = name_end;
10272b15cb3dSCy Schubert 	return 0;
10282b15cb3dSCy Schubert  err:
10292b15cb3dSCy Schubert 	return -1;
10302b15cb3dSCy Schubert }
10312b15cb3dSCy Schubert 
10322b15cb3dSCy Schubert /* parses a raw request from a nameserver */
10332b15cb3dSCy Schubert static int
reply_parse(struct evdns_base * base,u8 * packet,int length)10342b15cb3dSCy Schubert reply_parse(struct evdns_base *base, u8 *packet, int length) {
10352b15cb3dSCy Schubert 	int j = 0, k = 0;  /* index into packet */
10362b15cb3dSCy Schubert 	u16 t_;	 /* used by the macros */
10372b15cb3dSCy Schubert 	u32 t32_;  /* used by the macros */
10382b15cb3dSCy Schubert 	char tmp_name[256], cmp_name[256]; /* used by the macros */
10392b15cb3dSCy Schubert 	int name_matches = 0;
10402b15cb3dSCy Schubert 
10412b15cb3dSCy Schubert 	u16 trans_id, questions, answers, authority, additional, datalength;
10422b15cb3dSCy Schubert 	u16 flags = 0;
10432b15cb3dSCy Schubert 	u32 ttl, ttl_r = 0xffffffff;
10442b15cb3dSCy Schubert 	struct reply reply;
10452b15cb3dSCy Schubert 	struct request *req = NULL;
10462b15cb3dSCy Schubert 	unsigned int i;
10472b15cb3dSCy Schubert 
10482b15cb3dSCy Schubert 	ASSERT_LOCKED(base);
10492b15cb3dSCy Schubert 
10502b15cb3dSCy Schubert 	GET16(trans_id);
10512b15cb3dSCy Schubert 	GET16(flags);
10522b15cb3dSCy Schubert 	GET16(questions);
10532b15cb3dSCy Schubert 	GET16(answers);
10542b15cb3dSCy Schubert 	GET16(authority);
10552b15cb3dSCy Schubert 	GET16(additional);
10562b15cb3dSCy Schubert 	(void) authority; /* suppress "unused variable" warnings. */
10572b15cb3dSCy Schubert 	(void) additional; /* suppress "unused variable" warnings. */
10582b15cb3dSCy Schubert 
10592b15cb3dSCy Schubert 	req = request_find_from_trans_id(base, trans_id);
10602b15cb3dSCy Schubert 	if (!req) return -1;
10612b15cb3dSCy Schubert 	EVUTIL_ASSERT(req->base == base);
10622b15cb3dSCy Schubert 
10632b15cb3dSCy Schubert 	memset(&reply, 0, sizeof(reply));
10642b15cb3dSCy Schubert 
10652b15cb3dSCy Schubert 	/* If it's not an answer, it doesn't correspond to any request. */
1066*a466cc55SCy Schubert 	if (!(flags & _QR_MASK)) return -1;  /* must be an answer */
1067*a466cc55SCy Schubert 	if ((flags & (_RCODE_MASK|_TC_MASK)) && (flags & (_RCODE_MASK|_TC_MASK)) != DNS_ERR_NOTEXIST) {
10682b15cb3dSCy Schubert 		/* there was an error and it's not NXDOMAIN */
10692b15cb3dSCy Schubert 		goto err;
10702b15cb3dSCy Schubert 	}
10712b15cb3dSCy Schubert 	/* if (!answers) return; */  /* must have an answer of some form */
10722b15cb3dSCy Schubert 
10732b15cb3dSCy Schubert 	/* This macro skips a name in the DNS reply. */
10742b15cb3dSCy Schubert #define SKIP_NAME						\
10752b15cb3dSCy Schubert 	do { tmp_name[0] = '\0';				\
10762b15cb3dSCy Schubert 		if (name_parse(packet, length, &j, tmp_name,	\
10772b15cb3dSCy Schubert 			sizeof(tmp_name))<0)			\
10782b15cb3dSCy Schubert 			goto err;				\
10792b15cb3dSCy Schubert 	} while (0)
10802b15cb3dSCy Schubert 
10812b15cb3dSCy Schubert 	reply.type = req->request_type;
10822b15cb3dSCy Schubert 
10832b15cb3dSCy Schubert 	/* skip over each question in the reply */
10842b15cb3dSCy Schubert 	for (i = 0; i < questions; ++i) {
10852b15cb3dSCy Schubert 		/* the question looks like
10862b15cb3dSCy Schubert 		 *   <label:name><u16:type><u16:class>
10872b15cb3dSCy Schubert 		 */
1088*a466cc55SCy Schubert 		tmp_name[0] = '\0';
1089*a466cc55SCy Schubert 		cmp_name[0] = '\0';
1090*a466cc55SCy Schubert 		k = j;
1091*a466cc55SCy Schubert 		if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name)) < 0)
1092*a466cc55SCy Schubert 			goto err;
1093*a466cc55SCy Schubert 		if (name_parse(req->request, req->request_len, &k,
1094*a466cc55SCy Schubert 			cmp_name, sizeof(cmp_name))<0)
1095*a466cc55SCy Schubert 			goto err;
1096*a466cc55SCy Schubert 		if (!base->global_randomize_case) {
1097*a466cc55SCy Schubert 			if (strcmp(tmp_name, cmp_name) == 0)
1098*a466cc55SCy Schubert 				name_matches = 1;
1099*a466cc55SCy Schubert 		} else {
1100*a466cc55SCy Schubert 			if (evutil_ascii_strcasecmp(tmp_name, cmp_name) == 0)
1101*a466cc55SCy Schubert 				name_matches = 1;
1102*a466cc55SCy Schubert 		}
1103*a466cc55SCy Schubert 
11042b15cb3dSCy Schubert 		j += 4;
1105*a466cc55SCy Schubert 		if (j > length)
1106*a466cc55SCy Schubert 			goto err;
11072b15cb3dSCy Schubert 	}
11082b15cb3dSCy Schubert 
11092b15cb3dSCy Schubert 	if (!name_matches)
11102b15cb3dSCy Schubert 		goto err;
11112b15cb3dSCy Schubert 
11122b15cb3dSCy Schubert 	/* now we have the answer section which looks like
11132b15cb3dSCy Schubert 	 * <label:name><u16:type><u16:class><u32:ttl><u16:len><data...>
11142b15cb3dSCy Schubert 	 */
11152b15cb3dSCy Schubert 
11162b15cb3dSCy Schubert 	for (i = 0; i < answers; ++i) {
11172b15cb3dSCy Schubert 		u16 type, class;
11182b15cb3dSCy Schubert 
11192b15cb3dSCy Schubert 		SKIP_NAME;
11202b15cb3dSCy Schubert 		GET16(type);
11212b15cb3dSCy Schubert 		GET16(class);
11222b15cb3dSCy Schubert 		GET32(ttl);
11232b15cb3dSCy Schubert 		GET16(datalength);
11242b15cb3dSCy Schubert 
11252b15cb3dSCy Schubert 		if (type == TYPE_A && class == CLASS_INET) {
11262b15cb3dSCy Schubert 			int addrcount, addrtocopy;
11272b15cb3dSCy Schubert 			if (req->request_type != TYPE_A) {
11282b15cb3dSCy Schubert 				j += datalength; continue;
11292b15cb3dSCy Schubert 			}
11302b15cb3dSCy Schubert 			if ((datalength & 3) != 0) /* not an even number of As. */
11312b15cb3dSCy Schubert 			    goto err;
11322b15cb3dSCy Schubert 			addrcount = datalength >> 2;
11332b15cb3dSCy Schubert 			addrtocopy = MIN(MAX_V4_ADDRS - reply.data.a.addrcount, (unsigned)addrcount);
11342b15cb3dSCy Schubert 
11352b15cb3dSCy Schubert 			ttl_r = MIN(ttl_r, ttl);
11362b15cb3dSCy Schubert 			/* we only bother with the first four addresses. */
11372b15cb3dSCy Schubert 			if (j + 4*addrtocopy > length) goto err;
11382b15cb3dSCy Schubert 			memcpy(&reply.data.a.addresses[reply.data.a.addrcount],
11392b15cb3dSCy Schubert 				   packet + j, 4*addrtocopy);
11402b15cb3dSCy Schubert 			j += 4*addrtocopy;
11412b15cb3dSCy Schubert 			reply.data.a.addrcount += addrtocopy;
11422b15cb3dSCy Schubert 			reply.have_answer = 1;
11432b15cb3dSCy Schubert 			if (reply.data.a.addrcount == MAX_V4_ADDRS) break;
11442b15cb3dSCy Schubert 		} else if (type == TYPE_PTR && class == CLASS_INET) {
11452b15cb3dSCy Schubert 			if (req->request_type != TYPE_PTR) {
11462b15cb3dSCy Schubert 				j += datalength; continue;
11472b15cb3dSCy Schubert 			}
11482b15cb3dSCy Schubert 			if (name_parse(packet, length, &j, reply.data.ptr.name,
11492b15cb3dSCy Schubert 						   sizeof(reply.data.ptr.name))<0)
11502b15cb3dSCy Schubert 				goto err;
11512b15cb3dSCy Schubert 			ttl_r = MIN(ttl_r, ttl);
11522b15cb3dSCy Schubert 			reply.have_answer = 1;
11532b15cb3dSCy Schubert 			break;
11542b15cb3dSCy Schubert 		} else if (type == TYPE_CNAME) {
11552b15cb3dSCy Schubert 			char cname[HOST_NAME_MAX];
11562b15cb3dSCy Schubert 			if (!req->put_cname_in_ptr || *req->put_cname_in_ptr) {
11572b15cb3dSCy Schubert 				j += datalength; continue;
11582b15cb3dSCy Schubert 			}
11592b15cb3dSCy Schubert 			if (name_parse(packet, length, &j, cname,
11602b15cb3dSCy Schubert 				sizeof(cname))<0)
11612b15cb3dSCy Schubert 				goto err;
11622b15cb3dSCy Schubert 			*req->put_cname_in_ptr = mm_strdup(cname);
11632b15cb3dSCy Schubert 		} else if (type == TYPE_AAAA && class == CLASS_INET) {
11642b15cb3dSCy Schubert 			int addrcount, addrtocopy;
11652b15cb3dSCy Schubert 			if (req->request_type != TYPE_AAAA) {
11662b15cb3dSCy Schubert 				j += datalength; continue;
11672b15cb3dSCy Schubert 			}
11682b15cb3dSCy Schubert 			if ((datalength & 15) != 0) /* not an even number of AAAAs. */
11692b15cb3dSCy Schubert 				goto err;
11702b15cb3dSCy Schubert 			addrcount = datalength >> 4;  /* each address is 16 bytes long */
11712b15cb3dSCy Schubert 			addrtocopy = MIN(MAX_V6_ADDRS - reply.data.aaaa.addrcount, (unsigned)addrcount);
11722b15cb3dSCy Schubert 			ttl_r = MIN(ttl_r, ttl);
11732b15cb3dSCy Schubert 
11742b15cb3dSCy Schubert 			/* we only bother with the first four addresses. */
11752b15cb3dSCy Schubert 			if (j + 16*addrtocopy > length) goto err;
11762b15cb3dSCy Schubert 			memcpy(&reply.data.aaaa.addresses[reply.data.aaaa.addrcount],
11772b15cb3dSCy Schubert 				   packet + j, 16*addrtocopy);
11782b15cb3dSCy Schubert 			reply.data.aaaa.addrcount += addrtocopy;
11792b15cb3dSCy Schubert 			j += 16*addrtocopy;
11802b15cb3dSCy Schubert 			reply.have_answer = 1;
11812b15cb3dSCy Schubert 			if (reply.data.aaaa.addrcount == MAX_V6_ADDRS) break;
11822b15cb3dSCy Schubert 		} else {
11832b15cb3dSCy Schubert 			/* skip over any other type of resource */
11842b15cb3dSCy Schubert 			j += datalength;
11852b15cb3dSCy Schubert 		}
11862b15cb3dSCy Schubert 	}
11872b15cb3dSCy Schubert 
11882b15cb3dSCy Schubert 	if (!reply.have_answer) {
11892b15cb3dSCy Schubert 		for (i = 0; i < authority; ++i) {
11902b15cb3dSCy Schubert 			u16 type, class;
11912b15cb3dSCy Schubert 			SKIP_NAME;
11922b15cb3dSCy Schubert 			GET16(type);
11932b15cb3dSCy Schubert 			GET16(class);
11942b15cb3dSCy Schubert 			GET32(ttl);
11952b15cb3dSCy Schubert 			GET16(datalength);
11962b15cb3dSCy Schubert 			if (type == TYPE_SOA && class == CLASS_INET) {
11972b15cb3dSCy Schubert 				u32 serial, refresh, retry, expire, minimum;
11982b15cb3dSCy Schubert 				SKIP_NAME;
11992b15cb3dSCy Schubert 				SKIP_NAME;
12002b15cb3dSCy Schubert 				GET32(serial);
12012b15cb3dSCy Schubert 				GET32(refresh);
12022b15cb3dSCy Schubert 				GET32(retry);
12032b15cb3dSCy Schubert 				GET32(expire);
12042b15cb3dSCy Schubert 				GET32(minimum);
12052b15cb3dSCy Schubert 				(void)expire;
12062b15cb3dSCy Schubert 				(void)retry;
12072b15cb3dSCy Schubert 				(void)refresh;
12082b15cb3dSCy Schubert 				(void)serial;
12092b15cb3dSCy Schubert 				ttl_r = MIN(ttl_r, ttl);
12102b15cb3dSCy Schubert 				ttl_r = MIN(ttl_r, minimum);
12112b15cb3dSCy Schubert 			} else {
12122b15cb3dSCy Schubert 				/* skip over any other type of resource */
12132b15cb3dSCy Schubert 				j += datalength;
12142b15cb3dSCy Schubert 			}
12152b15cb3dSCy Schubert 		}
12162b15cb3dSCy Schubert 	}
12172b15cb3dSCy Schubert 
12182b15cb3dSCy Schubert 	if (ttl_r == 0xffffffff)
12192b15cb3dSCy Schubert 		ttl_r = 0;
12202b15cb3dSCy Schubert 
12212b15cb3dSCy Schubert 	reply_handle(req, flags, ttl_r, &reply);
12222b15cb3dSCy Schubert 	return 0;
12232b15cb3dSCy Schubert  err:
12242b15cb3dSCy Schubert 	if (req)
12252b15cb3dSCy Schubert 		reply_handle(req, flags, 0, NULL);
12262b15cb3dSCy Schubert 	return -1;
12272b15cb3dSCy Schubert }
12282b15cb3dSCy Schubert 
12292b15cb3dSCy Schubert /* Parse a raw request (packet,length) sent to a nameserver port (port) from */
12302b15cb3dSCy Schubert /* a DNS client (addr,addrlen), and if it's well-formed, call the corresponding */
12312b15cb3dSCy Schubert /* callback. */
12322b15cb3dSCy Schubert static int
request_parse(u8 * packet,int length,struct evdns_server_port * port,struct sockaddr * addr,ev_socklen_t addrlen)12332b15cb3dSCy Schubert request_parse(u8 *packet, int length, struct evdns_server_port *port, struct sockaddr *addr, ev_socklen_t addrlen)
12342b15cb3dSCy Schubert {
12352b15cb3dSCy Schubert 	int j = 0;	/* index into packet */
12362b15cb3dSCy Schubert 	u16 t_;	 /* used by the macros */
12372b15cb3dSCy Schubert 	char tmp_name[256]; /* used by the macros */
12382b15cb3dSCy Schubert 
12392b15cb3dSCy Schubert 	int i;
12402b15cb3dSCy Schubert 	u16 trans_id, flags, questions, answers, authority, additional;
12412b15cb3dSCy Schubert 	struct server_request *server_req = NULL;
12422b15cb3dSCy Schubert 
12432b15cb3dSCy Schubert 	ASSERT_LOCKED(port);
12442b15cb3dSCy Schubert 
12452b15cb3dSCy Schubert 	/* Get the header fields */
12462b15cb3dSCy Schubert 	GET16(trans_id);
12472b15cb3dSCy Schubert 	GET16(flags);
12482b15cb3dSCy Schubert 	GET16(questions);
12492b15cb3dSCy Schubert 	GET16(answers);
12502b15cb3dSCy Schubert 	GET16(authority);
12512b15cb3dSCy Schubert 	GET16(additional);
12522b15cb3dSCy Schubert 	(void)answers;
12532b15cb3dSCy Schubert 	(void)additional;
12542b15cb3dSCy Schubert 	(void)authority;
12552b15cb3dSCy Schubert 
1256*a466cc55SCy Schubert 	if (flags & _QR_MASK) return -1; /* Must not be an answer. */
1257*a466cc55SCy Schubert 	flags &= (_RD_MASK|_CD_MASK); /* Only RD and CD get preserved. */
12582b15cb3dSCy Schubert 
12592b15cb3dSCy Schubert 	server_req = mm_malloc(sizeof(struct server_request));
12602b15cb3dSCy Schubert 	if (server_req == NULL) return -1;
12612b15cb3dSCy Schubert 	memset(server_req, 0, sizeof(struct server_request));
12622b15cb3dSCy Schubert 
12632b15cb3dSCy Schubert 	server_req->trans_id = trans_id;
12642b15cb3dSCy Schubert 	memcpy(&server_req->addr, addr, addrlen);
12652b15cb3dSCy Schubert 	server_req->addrlen = addrlen;
12662b15cb3dSCy Schubert 
12672b15cb3dSCy Schubert 	server_req->base.flags = flags;
12682b15cb3dSCy Schubert 	server_req->base.nquestions = 0;
12692b15cb3dSCy Schubert 	server_req->base.questions = mm_calloc(sizeof(struct evdns_server_question *), questions);
12702b15cb3dSCy Schubert 	if (server_req->base.questions == NULL)
12712b15cb3dSCy Schubert 		goto err;
12722b15cb3dSCy Schubert 
12732b15cb3dSCy Schubert 	for (i = 0; i < questions; ++i) {
12742b15cb3dSCy Schubert 		u16 type, class;
12752b15cb3dSCy Schubert 		struct evdns_server_question *q;
12762b15cb3dSCy Schubert 		int namelen;
12772b15cb3dSCy Schubert 		if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0)
12782b15cb3dSCy Schubert 			goto err;
12792b15cb3dSCy Schubert 		GET16(type);
12802b15cb3dSCy Schubert 		GET16(class);
12812b15cb3dSCy Schubert 		namelen = (int)strlen(tmp_name);
12822b15cb3dSCy Schubert 		q = mm_malloc(sizeof(struct evdns_server_question) + namelen);
12832b15cb3dSCy Schubert 		if (!q)
12842b15cb3dSCy Schubert 			goto err;
12852b15cb3dSCy Schubert 		q->type = type;
12862b15cb3dSCy Schubert 		q->dns_question_class = class;
12872b15cb3dSCy Schubert 		memcpy(q->name, tmp_name, namelen+1);
12882b15cb3dSCy Schubert 		server_req->base.questions[server_req->base.nquestions++] = q;
12892b15cb3dSCy Schubert 	}
12902b15cb3dSCy Schubert 
12912b15cb3dSCy Schubert 	/* Ignore answers, authority, and additional. */
12922b15cb3dSCy Schubert 
12932b15cb3dSCy Schubert 	server_req->port = port;
12942b15cb3dSCy Schubert 	port->refcnt++;
12952b15cb3dSCy Schubert 
12962b15cb3dSCy Schubert 	/* Only standard queries are supported. */
1297*a466cc55SCy Schubert 	if (flags & _OP_MASK) {
12982b15cb3dSCy Schubert 		evdns_server_request_respond(&(server_req->base), DNS_ERR_NOTIMPL);
12992b15cb3dSCy Schubert 		return -1;
13002b15cb3dSCy Schubert 	}
13012b15cb3dSCy Schubert 
13022b15cb3dSCy Schubert 	port->user_callback(&(server_req->base), port->user_data);
13032b15cb3dSCy Schubert 
13042b15cb3dSCy Schubert 	return 0;
13052b15cb3dSCy Schubert err:
13062b15cb3dSCy Schubert 	if (server_req->base.questions) {
13072b15cb3dSCy Schubert 		for (i = 0; i < server_req->base.nquestions; ++i)
13082b15cb3dSCy Schubert 			mm_free(server_req->base.questions[i]);
13092b15cb3dSCy Schubert 		mm_free(server_req->base.questions);
13102b15cb3dSCy Schubert 	}
13112b15cb3dSCy Schubert 	mm_free(server_req);
13122b15cb3dSCy Schubert 	return -1;
13132b15cb3dSCy Schubert 
13142b15cb3dSCy Schubert #undef SKIP_NAME
13152b15cb3dSCy Schubert #undef GET32
13162b15cb3dSCy Schubert #undef GET16
13172b15cb3dSCy Schubert #undef GET8
13182b15cb3dSCy Schubert }
13192b15cb3dSCy Schubert 
13202b15cb3dSCy Schubert 
13212b15cb3dSCy Schubert void
evdns_set_transaction_id_fn(ev_uint16_t (* fn)(void))13222b15cb3dSCy Schubert evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void))
13232b15cb3dSCy Schubert {
13242b15cb3dSCy Schubert }
13252b15cb3dSCy Schubert 
13262b15cb3dSCy Schubert void
evdns_set_random_bytes_fn(void (* fn)(char *,size_t))13272b15cb3dSCy Schubert evdns_set_random_bytes_fn(void (*fn)(char *, size_t))
13282b15cb3dSCy Schubert {
13292b15cb3dSCy Schubert }
13302b15cb3dSCy Schubert 
13312b15cb3dSCy Schubert /* Try to choose a strong transaction id which isn't already in flight */
13322b15cb3dSCy Schubert static u16
transaction_id_pick(struct evdns_base * base)13332b15cb3dSCy Schubert transaction_id_pick(struct evdns_base *base) {
13342b15cb3dSCy Schubert 	ASSERT_LOCKED(base);
13352b15cb3dSCy Schubert 	for (;;) {
13362b15cb3dSCy Schubert 		u16 trans_id;
13372b15cb3dSCy Schubert 		evutil_secure_rng_get_bytes(&trans_id, sizeof(trans_id));
13382b15cb3dSCy Schubert 
13392b15cb3dSCy Schubert 		if (trans_id == 0xffff) continue;
13402b15cb3dSCy Schubert 		/* now check to see if that id is already inflight */
13412b15cb3dSCy Schubert 		if (request_find_from_trans_id(base, trans_id) == NULL)
13422b15cb3dSCy Schubert 			return trans_id;
13432b15cb3dSCy Schubert 	}
13442b15cb3dSCy Schubert }
13452b15cb3dSCy Schubert 
13462b15cb3dSCy Schubert /* choose a namesever to use. This function will try to ignore */
13472b15cb3dSCy Schubert /* nameservers which we think are down and load balance across the rest */
13482b15cb3dSCy Schubert /* by updating the server_head global each time. */
13492b15cb3dSCy Schubert static struct nameserver *
nameserver_pick(struct evdns_base * base)13502b15cb3dSCy Schubert nameserver_pick(struct evdns_base *base) {
13512b15cb3dSCy Schubert 	struct nameserver *started_at = base->server_head, *picked;
13522b15cb3dSCy Schubert 	ASSERT_LOCKED(base);
13532b15cb3dSCy Schubert 	if (!base->server_head) return NULL;
13542b15cb3dSCy Schubert 
13552b15cb3dSCy Schubert 	/* if we don't have any good nameservers then there's no */
13562b15cb3dSCy Schubert 	/* point in trying to find one. */
13572b15cb3dSCy Schubert 	if (!base->global_good_nameservers) {
13582b15cb3dSCy Schubert 		base->server_head = base->server_head->next;
13592b15cb3dSCy Schubert 		return base->server_head;
13602b15cb3dSCy Schubert 	}
13612b15cb3dSCy Schubert 
13622b15cb3dSCy Schubert 	/* remember that nameservers are in a circular list */
13632b15cb3dSCy Schubert 	for (;;) {
13642b15cb3dSCy Schubert 		if (base->server_head->state) {
13652b15cb3dSCy Schubert 			/* we think this server is currently good */
13662b15cb3dSCy Schubert 			picked = base->server_head;
13672b15cb3dSCy Schubert 			base->server_head = base->server_head->next;
13682b15cb3dSCy Schubert 			return picked;
13692b15cb3dSCy Schubert 		}
13702b15cb3dSCy Schubert 
13712b15cb3dSCy Schubert 		base->server_head = base->server_head->next;
13722b15cb3dSCy Schubert 		if (base->server_head == started_at) {
13732b15cb3dSCy Schubert 			/* all the nameservers seem to be down */
13742b15cb3dSCy Schubert 			/* so we just return this one and hope for the */
13752b15cb3dSCy Schubert 			/* best */
13762b15cb3dSCy Schubert 			EVUTIL_ASSERT(base->global_good_nameservers == 0);
13772b15cb3dSCy Schubert 			picked = base->server_head;
13782b15cb3dSCy Schubert 			base->server_head = base->server_head->next;
13792b15cb3dSCy Schubert 			return picked;
13802b15cb3dSCy Schubert 		}
13812b15cb3dSCy Schubert 	}
13822b15cb3dSCy Schubert }
13832b15cb3dSCy Schubert 
13842b15cb3dSCy Schubert /* this is called when a namesever socket is ready for reading */
13852b15cb3dSCy Schubert static void
nameserver_read(struct nameserver * ns)13862b15cb3dSCy Schubert nameserver_read(struct nameserver *ns) {
13872b15cb3dSCy Schubert 	struct sockaddr_storage ss;
13882b15cb3dSCy Schubert 	ev_socklen_t addrlen = sizeof(ss);
13892b15cb3dSCy Schubert 	u8 packet[1500];
13902b15cb3dSCy Schubert 	char addrbuf[128];
13912b15cb3dSCy Schubert 	ASSERT_LOCKED(ns->base);
13922b15cb3dSCy Schubert 
13932b15cb3dSCy Schubert 	for (;;) {
13942b15cb3dSCy Schubert 		const int r = recvfrom(ns->socket, (void*)packet,
13952b15cb3dSCy Schubert 		    sizeof(packet), 0,
13962b15cb3dSCy Schubert 		    (struct sockaddr*)&ss, &addrlen);
13972b15cb3dSCy Schubert 		if (r < 0) {
13982b15cb3dSCy Schubert 			int err = evutil_socket_geterror(ns->socket);
13992b15cb3dSCy Schubert 			if (EVUTIL_ERR_RW_RETRIABLE(err))
14002b15cb3dSCy Schubert 				return;
14012b15cb3dSCy Schubert 			nameserver_failed(ns,
14022b15cb3dSCy Schubert 			    evutil_socket_error_to_string(err));
14032b15cb3dSCy Schubert 			return;
14042b15cb3dSCy Schubert 		}
14052b15cb3dSCy Schubert 		if (evutil_sockaddr_cmp((struct sockaddr*)&ss,
14062b15cb3dSCy Schubert 			(struct sockaddr*)&ns->address, 0)) {
14072b15cb3dSCy Schubert 			log(EVDNS_LOG_WARN, "Address mismatch on received "
14082b15cb3dSCy Schubert 			    "DNS packet.  Apparent source was %s",
14092b15cb3dSCy Schubert 			    evutil_format_sockaddr_port_(
14102b15cb3dSCy Schubert 				    (struct sockaddr *)&ss,
14112b15cb3dSCy Schubert 				    addrbuf, sizeof(addrbuf)));
14122b15cb3dSCy Schubert 			return;
14132b15cb3dSCy Schubert 		}
14142b15cb3dSCy Schubert 
14152b15cb3dSCy Schubert 		ns->timedout = 0;
14162b15cb3dSCy Schubert 		reply_parse(ns->base, packet, r);
14172b15cb3dSCy Schubert 	}
14182b15cb3dSCy Schubert }
14192b15cb3dSCy Schubert 
14202b15cb3dSCy Schubert /* Read a packet from a DNS client on a server port s, parse it, and */
14212b15cb3dSCy Schubert /* act accordingly. */
14222b15cb3dSCy Schubert static void
server_port_read(struct evdns_server_port * s)14232b15cb3dSCy Schubert server_port_read(struct evdns_server_port *s) {
14242b15cb3dSCy Schubert 	u8 packet[1500];
14252b15cb3dSCy Schubert 	struct sockaddr_storage addr;
14262b15cb3dSCy Schubert 	ev_socklen_t addrlen;
14272b15cb3dSCy Schubert 	int r;
14282b15cb3dSCy Schubert 	ASSERT_LOCKED(s);
14292b15cb3dSCy Schubert 
14302b15cb3dSCy Schubert 	for (;;) {
14312b15cb3dSCy Schubert 		addrlen = sizeof(struct sockaddr_storage);
14322b15cb3dSCy Schubert 		r = recvfrom(s->socket, (void*)packet, sizeof(packet), 0,
14332b15cb3dSCy Schubert 					 (struct sockaddr*) &addr, &addrlen);
14342b15cb3dSCy Schubert 		if (r < 0) {
14352b15cb3dSCy Schubert 			int err = evutil_socket_geterror(s->socket);
14362b15cb3dSCy Schubert 			if (EVUTIL_ERR_RW_RETRIABLE(err))
14372b15cb3dSCy Schubert 				return;
14382b15cb3dSCy Schubert 			log(EVDNS_LOG_WARN,
14392b15cb3dSCy Schubert 			    "Error %s (%d) while reading request.",
14402b15cb3dSCy Schubert 			    evutil_socket_error_to_string(err), err);
14412b15cb3dSCy Schubert 			return;
14422b15cb3dSCy Schubert 		}
14432b15cb3dSCy Schubert 		request_parse(packet, r, s, (struct sockaddr*) &addr, addrlen);
14442b15cb3dSCy Schubert 	}
14452b15cb3dSCy Schubert }
14462b15cb3dSCy Schubert 
14472b15cb3dSCy Schubert /* Try to write all pending replies on a given DNS server port. */
14482b15cb3dSCy Schubert static void
server_port_flush(struct evdns_server_port * port)14492b15cb3dSCy Schubert server_port_flush(struct evdns_server_port *port)
14502b15cb3dSCy Schubert {
14512b15cb3dSCy Schubert 	struct server_request *req = port->pending_replies;
14522b15cb3dSCy Schubert 	ASSERT_LOCKED(port);
14532b15cb3dSCy Schubert 	while (req) {
14542b15cb3dSCy Schubert 		int r = sendto(port->socket, req->response, (int)req->response_len, 0,
14552b15cb3dSCy Schubert 			   (struct sockaddr*) &req->addr, (ev_socklen_t)req->addrlen);
14562b15cb3dSCy Schubert 		if (r < 0) {
14572b15cb3dSCy Schubert 			int err = evutil_socket_geterror(port->socket);
14582b15cb3dSCy Schubert 			if (EVUTIL_ERR_RW_RETRIABLE(err))
14592b15cb3dSCy Schubert 				return;
14602b15cb3dSCy Schubert 			log(EVDNS_LOG_WARN, "Error %s (%d) while writing response to port; dropping", evutil_socket_error_to_string(err), err);
14612b15cb3dSCy Schubert 		}
14622b15cb3dSCy Schubert 		if (server_request_free(req)) {
14632b15cb3dSCy Schubert 			/* we released the last reference to req->port. */
14642b15cb3dSCy Schubert 			return;
14652b15cb3dSCy Schubert 		} else {
14662b15cb3dSCy Schubert 			EVUTIL_ASSERT(req != port->pending_replies);
14672b15cb3dSCy Schubert 			req = port->pending_replies;
14682b15cb3dSCy Schubert 		}
14692b15cb3dSCy Schubert 	}
14702b15cb3dSCy Schubert 
14712b15cb3dSCy Schubert 	/* We have no more pending requests; stop listening for 'writeable' events. */
14722b15cb3dSCy Schubert 	(void) event_del(&port->event);
14732b15cb3dSCy Schubert 	event_assign(&port->event, port->event_base,
14742b15cb3dSCy Schubert 				 port->socket, EV_READ | EV_PERSIST,
14752b15cb3dSCy Schubert 				 server_port_ready_callback, port);
14762b15cb3dSCy Schubert 
14772b15cb3dSCy Schubert 	if (event_add(&port->event, NULL) < 0) {
14782b15cb3dSCy Schubert 		log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server.");
14792b15cb3dSCy Schubert 		/* ???? Do more? */
14802b15cb3dSCy Schubert 	}
14812b15cb3dSCy Schubert }
14822b15cb3dSCy Schubert 
14832b15cb3dSCy Schubert /* set if we are waiting for the ability to write to this server. */
14842b15cb3dSCy Schubert /* if waiting is true then we ask libevent for EV_WRITE events, otherwise */
14852b15cb3dSCy Schubert /* we stop these events. */
14862b15cb3dSCy Schubert static void
nameserver_write_waiting(struct nameserver * ns,char waiting)14872b15cb3dSCy Schubert nameserver_write_waiting(struct nameserver *ns, char waiting) {
14882b15cb3dSCy Schubert 	ASSERT_LOCKED(ns->base);
14892b15cb3dSCy Schubert 	if (ns->write_waiting == waiting) return;
14902b15cb3dSCy Schubert 
14912b15cb3dSCy Schubert 	ns->write_waiting = waiting;
14922b15cb3dSCy Schubert 	(void) event_del(&ns->event);
14932b15cb3dSCy Schubert 	event_assign(&ns->event, ns->base->event_base,
14942b15cb3dSCy Schubert 	    ns->socket, EV_READ | (waiting ? EV_WRITE : 0) | EV_PERSIST,
14952b15cb3dSCy Schubert 	    nameserver_ready_callback, ns);
14962b15cb3dSCy Schubert 	if (event_add(&ns->event, NULL) < 0) {
14972b15cb3dSCy Schubert 		char addrbuf[128];
14982b15cb3dSCy Schubert 		log(EVDNS_LOG_WARN, "Error from libevent when adding event for %s",
14992b15cb3dSCy Schubert 		    evutil_format_sockaddr_port_(
15002b15cb3dSCy Schubert 			    (struct sockaddr *)&ns->address,
15012b15cb3dSCy Schubert 			    addrbuf, sizeof(addrbuf)));
15022b15cb3dSCy Schubert 		/* ???? Do more? */
15032b15cb3dSCy Schubert 	}
15042b15cb3dSCy Schubert }
15052b15cb3dSCy Schubert 
15062b15cb3dSCy Schubert /* a callback function. Called by libevent when the kernel says that */
15072b15cb3dSCy Schubert /* a nameserver socket is ready for writing or reading */
15082b15cb3dSCy Schubert static void
nameserver_ready_callback(evutil_socket_t fd,short events,void * arg)15092b15cb3dSCy Schubert nameserver_ready_callback(evutil_socket_t fd, short events, void *arg) {
15102b15cb3dSCy Schubert 	struct nameserver *ns = (struct nameserver *) arg;
15112b15cb3dSCy Schubert 	(void)fd;
15122b15cb3dSCy Schubert 
15132b15cb3dSCy Schubert 	EVDNS_LOCK(ns->base);
15142b15cb3dSCy Schubert 	if (events & EV_WRITE) {
15152b15cb3dSCy Schubert 		ns->choked = 0;
15162b15cb3dSCy Schubert 		if (!evdns_transmit(ns->base)) {
15172b15cb3dSCy Schubert 			nameserver_write_waiting(ns, 0);
15182b15cb3dSCy Schubert 		}
15192b15cb3dSCy Schubert 	}
15202b15cb3dSCy Schubert 	if (events & EV_READ) {
15212b15cb3dSCy Schubert 		nameserver_read(ns);
15222b15cb3dSCy Schubert 	}
15232b15cb3dSCy Schubert 	EVDNS_UNLOCK(ns->base);
15242b15cb3dSCy Schubert }
15252b15cb3dSCy Schubert 
15262b15cb3dSCy Schubert /* a callback function. Called by libevent when the kernel says that */
15272b15cb3dSCy Schubert /* a server socket is ready for writing or reading. */
15282b15cb3dSCy Schubert static void
server_port_ready_callback(evutil_socket_t fd,short events,void * arg)15292b15cb3dSCy Schubert server_port_ready_callback(evutil_socket_t fd, short events, void *arg) {
15302b15cb3dSCy Schubert 	struct evdns_server_port *port = (struct evdns_server_port *) arg;
15312b15cb3dSCy Schubert 	(void) fd;
15322b15cb3dSCy Schubert 
15332b15cb3dSCy Schubert 	EVDNS_LOCK(port);
15342b15cb3dSCy Schubert 	if (events & EV_WRITE) {
15352b15cb3dSCy Schubert 		port->choked = 0;
15362b15cb3dSCy Schubert 		server_port_flush(port);
15372b15cb3dSCy Schubert 	}
15382b15cb3dSCy Schubert 	if (events & EV_READ) {
15392b15cb3dSCy Schubert 		server_port_read(port);
15402b15cb3dSCy Schubert 	}
15412b15cb3dSCy Schubert 	EVDNS_UNLOCK(port);
15422b15cb3dSCy Schubert }
15432b15cb3dSCy Schubert 
15442b15cb3dSCy Schubert /* This is an inefficient representation; only use it via the dnslabel_table_*
15452b15cb3dSCy Schubert  * functions, so that is can be safely replaced with something smarter later. */
15462b15cb3dSCy Schubert #define MAX_LABELS 128
15472b15cb3dSCy Schubert /* Structures used to implement name compression */
15482b15cb3dSCy Schubert struct dnslabel_entry { char *v; off_t pos; };
15492b15cb3dSCy Schubert struct dnslabel_table {
15502b15cb3dSCy Schubert 	int n_labels; /* number of current entries */
15512b15cb3dSCy Schubert 	/* map from name to position in message */
15522b15cb3dSCy Schubert 	struct dnslabel_entry labels[MAX_LABELS];
15532b15cb3dSCy Schubert };
15542b15cb3dSCy Schubert 
15552b15cb3dSCy Schubert /* Initialize dnslabel_table. */
15562b15cb3dSCy Schubert static void
dnslabel_table_init(struct dnslabel_table * table)15572b15cb3dSCy Schubert dnslabel_table_init(struct dnslabel_table *table)
15582b15cb3dSCy Schubert {
15592b15cb3dSCy Schubert 	table->n_labels = 0;
15602b15cb3dSCy Schubert }
15612b15cb3dSCy Schubert 
15622b15cb3dSCy Schubert /* Free all storage held by table, but not the table itself. */
15632b15cb3dSCy Schubert static void
dnslabel_clear(struct dnslabel_table * table)15642b15cb3dSCy Schubert dnslabel_clear(struct dnslabel_table *table)
15652b15cb3dSCy Schubert {
15662b15cb3dSCy Schubert 	int i;
15672b15cb3dSCy Schubert 	for (i = 0; i < table->n_labels; ++i)
15682b15cb3dSCy Schubert 		mm_free(table->labels[i].v);
15692b15cb3dSCy Schubert 	table->n_labels = 0;
15702b15cb3dSCy Schubert }
15712b15cb3dSCy Schubert 
15722b15cb3dSCy Schubert /* return the position of the label in the current message, or -1 if the label */
15732b15cb3dSCy Schubert /* hasn't been used yet. */
15742b15cb3dSCy Schubert static int
dnslabel_table_get_pos(const struct dnslabel_table * table,const char * label)15752b15cb3dSCy Schubert dnslabel_table_get_pos(const struct dnslabel_table *table, const char *label)
15762b15cb3dSCy Schubert {
15772b15cb3dSCy Schubert 	int i;
15782b15cb3dSCy Schubert 	for (i = 0; i < table->n_labels; ++i) {
15792b15cb3dSCy Schubert 		if (!strcmp(label, table->labels[i].v))
15802b15cb3dSCy Schubert 			return table->labels[i].pos;
15812b15cb3dSCy Schubert 	}
15822b15cb3dSCy Schubert 	return -1;
15832b15cb3dSCy Schubert }
15842b15cb3dSCy Schubert 
15852b15cb3dSCy Schubert /* remember that we've used the label at position pos */
15862b15cb3dSCy Schubert static int
dnslabel_table_add(struct dnslabel_table * table,const char * label,off_t pos)15872b15cb3dSCy Schubert dnslabel_table_add(struct dnslabel_table *table, const char *label, off_t pos)
15882b15cb3dSCy Schubert {
15892b15cb3dSCy Schubert 	char *v;
15902b15cb3dSCy Schubert 	int p;
15912b15cb3dSCy Schubert 	if (table->n_labels == MAX_LABELS)
15922b15cb3dSCy Schubert 		return (-1);
15932b15cb3dSCy Schubert 	v = mm_strdup(label);
15942b15cb3dSCy Schubert 	if (v == NULL)
15952b15cb3dSCy Schubert 		return (-1);
15962b15cb3dSCy Schubert 	p = table->n_labels++;
15972b15cb3dSCy Schubert 	table->labels[p].v = v;
15982b15cb3dSCy Schubert 	table->labels[p].pos = pos;
15992b15cb3dSCy Schubert 
16002b15cb3dSCy Schubert 	return (0);
16012b15cb3dSCy Schubert }
16022b15cb3dSCy Schubert 
16032b15cb3dSCy Schubert /* Converts a string to a length-prefixed set of DNS labels, starting */
16042b15cb3dSCy Schubert /* at buf[j]. name and buf must not overlap. name_len should be the length */
16052b15cb3dSCy Schubert /* of name.	 table is optional, and is used for compression. */
16062b15cb3dSCy Schubert /* */
16072b15cb3dSCy Schubert /* Input: abc.def */
16082b15cb3dSCy Schubert /* Output: <3>abc<3>def<0> */
16092b15cb3dSCy Schubert /* */
16102b15cb3dSCy Schubert /* Returns the first index after the encoded name, or negative on error. */
16112b15cb3dSCy Schubert /*	 -1	 label was > 63 bytes */
16122b15cb3dSCy Schubert /*	 -2	 name too long to fit in buffer. */
16132b15cb3dSCy Schubert /* */
16142b15cb3dSCy Schubert static off_t
dnsname_to_labels(u8 * const buf,size_t buf_len,off_t j,const char * name,const size_t name_len,struct dnslabel_table * table)16152b15cb3dSCy Schubert dnsname_to_labels(u8 *const buf, size_t buf_len, off_t j,
16162b15cb3dSCy Schubert 				  const char *name, const size_t name_len,
16172b15cb3dSCy Schubert 				  struct dnslabel_table *table) {
16182b15cb3dSCy Schubert 	const char *end = name + name_len;
16192b15cb3dSCy Schubert 	int ref = 0;
16202b15cb3dSCy Schubert 	u16 t_;
16212b15cb3dSCy Schubert 
16222b15cb3dSCy Schubert #define APPEND16(x) do {						\
16232b15cb3dSCy Schubert 		if (j + 2 > (off_t)buf_len)				\
16242b15cb3dSCy Schubert 			goto overflow;					\
16252b15cb3dSCy Schubert 		t_ = htons(x);						\
16262b15cb3dSCy Schubert 		memcpy(buf + j, &t_, 2);				\
16272b15cb3dSCy Schubert 		j += 2;							\
16282b15cb3dSCy Schubert 	} while (0)
16292b15cb3dSCy Schubert #define APPEND32(x) do {						\
16302b15cb3dSCy Schubert 		if (j + 4 > (off_t)buf_len)				\
16312b15cb3dSCy Schubert 			goto overflow;					\
16322b15cb3dSCy Schubert 		t32_ = htonl(x);					\
16332b15cb3dSCy Schubert 		memcpy(buf + j, &t32_, 4);				\
16342b15cb3dSCy Schubert 		j += 4;							\
16352b15cb3dSCy Schubert 	} while (0)
16362b15cb3dSCy Schubert 
16372b15cb3dSCy Schubert 	if (name_len > 255) return -2;
16382b15cb3dSCy Schubert 
16392b15cb3dSCy Schubert 	for (;;) {
16402b15cb3dSCy Schubert 		const char *const start = name;
16412b15cb3dSCy Schubert 		if (table && (ref = dnslabel_table_get_pos(table, name)) >= 0) {
16422b15cb3dSCy Schubert 			APPEND16(ref | 0xc000);
16432b15cb3dSCy Schubert 			return j;
16442b15cb3dSCy Schubert 		}
16452b15cb3dSCy Schubert 		name = strchr(name, '.');
16462b15cb3dSCy Schubert 		if (!name) {
16472b15cb3dSCy Schubert 			const size_t label_len = end - start;
16482b15cb3dSCy Schubert 			if (label_len > 63) return -1;
16492b15cb3dSCy Schubert 			if ((size_t)(j+label_len+1) > buf_len) return -2;
16502b15cb3dSCy Schubert 			if (table) dnslabel_table_add(table, start, j);
16512b15cb3dSCy Schubert 			buf[j++] = (ev_uint8_t)label_len;
16522b15cb3dSCy Schubert 
16532b15cb3dSCy Schubert 			memcpy(buf + j, start, label_len);
16542b15cb3dSCy Schubert 			j += (int) label_len;
16552b15cb3dSCy Schubert 			break;
16562b15cb3dSCy Schubert 		} else {
16572b15cb3dSCy Schubert 			/* append length of the label. */
16582b15cb3dSCy Schubert 			const size_t label_len = name - start;
16592b15cb3dSCy Schubert 			if (label_len > 63) return -1;
16602b15cb3dSCy Schubert 			if ((size_t)(j+label_len+1) > buf_len) return -2;
16612b15cb3dSCy Schubert 			if (table) dnslabel_table_add(table, start, j);
16622b15cb3dSCy Schubert 			buf[j++] = (ev_uint8_t)label_len;
16632b15cb3dSCy Schubert 
16642b15cb3dSCy Schubert 			memcpy(buf + j, start, label_len);
16652b15cb3dSCy Schubert 			j += (int) label_len;
16662b15cb3dSCy Schubert 			/* hop over the '.' */
16672b15cb3dSCy Schubert 			name++;
16682b15cb3dSCy Schubert 		}
16692b15cb3dSCy Schubert 	}
16702b15cb3dSCy Schubert 
16712b15cb3dSCy Schubert 	/* the labels must be terminated by a 0. */
16722b15cb3dSCy Schubert 	/* It's possible that the name ended in a . */
16732b15cb3dSCy Schubert 	/* in which case the zero is already there */
16742b15cb3dSCy Schubert 	if (!j || buf[j-1]) buf[j++] = 0;
16752b15cb3dSCy Schubert 	return j;
16762b15cb3dSCy Schubert  overflow:
16772b15cb3dSCy Schubert 	return (-2);
16782b15cb3dSCy Schubert }
16792b15cb3dSCy Schubert 
16802b15cb3dSCy Schubert /* Finds the length of a dns request for a DNS name of the given */
16812b15cb3dSCy Schubert /* length. The actual request may be smaller than the value returned */
16822b15cb3dSCy Schubert /* here */
16832b15cb3dSCy Schubert static size_t
evdns_request_len(const size_t name_len)16842b15cb3dSCy Schubert evdns_request_len(const size_t name_len) {
16852b15cb3dSCy Schubert 	return 96 + /* length of the DNS standard header */
16862b15cb3dSCy Schubert 		name_len + 2 +
16872b15cb3dSCy Schubert 		4;  /* space for the resource type */
16882b15cb3dSCy Schubert }
16892b15cb3dSCy Schubert 
16902b15cb3dSCy Schubert /* build a dns request packet into buf. buf should be at least as long */
16912b15cb3dSCy Schubert /* as evdns_request_len told you it should be. */
16922b15cb3dSCy Schubert /* */
16932b15cb3dSCy Schubert /* Returns the amount of space used. Negative on error. */
16942b15cb3dSCy Schubert static int
evdns_request_data_build(const char * const name,const size_t name_len,const u16 trans_id,const u16 type,const u16 class,u8 * const buf,size_t buf_len)16952b15cb3dSCy Schubert evdns_request_data_build(const char *const name, const size_t name_len,
16962b15cb3dSCy Schubert     const u16 trans_id, const u16 type, const u16 class,
16972b15cb3dSCy Schubert     u8 *const buf, size_t buf_len) {
16982b15cb3dSCy Schubert 	off_t j = 0;  /* current offset into buf */
16992b15cb3dSCy Schubert 	u16 t_;	 /* used by the macros */
17002b15cb3dSCy Schubert 
17012b15cb3dSCy Schubert 	APPEND16(trans_id);
17022b15cb3dSCy Schubert 	APPEND16(0x0100);  /* standard query, recusion needed */
17032b15cb3dSCy Schubert 	APPEND16(1);  /* one question */
17042b15cb3dSCy Schubert 	APPEND16(0);  /* no answers */
17052b15cb3dSCy Schubert 	APPEND16(0);  /* no authority */
17062b15cb3dSCy Schubert 	APPEND16(0);  /* no additional */
17072b15cb3dSCy Schubert 
17082b15cb3dSCy Schubert 	j = dnsname_to_labels(buf, buf_len, j, name, name_len, NULL);
17092b15cb3dSCy Schubert 	if (j < 0) {
17102b15cb3dSCy Schubert 		return (int)j;
17112b15cb3dSCy Schubert 	}
17122b15cb3dSCy Schubert 
17132b15cb3dSCy Schubert 	APPEND16(type);
17142b15cb3dSCy Schubert 	APPEND16(class);
17152b15cb3dSCy Schubert 
17162b15cb3dSCy Schubert 	return (int)j;
17172b15cb3dSCy Schubert  overflow:
17182b15cb3dSCy Schubert 	return (-1);
17192b15cb3dSCy Schubert }
17202b15cb3dSCy Schubert 
17212b15cb3dSCy Schubert /* exported function */
17222b15cb3dSCy Schubert struct evdns_server_port *
evdns_add_server_port_with_base(struct event_base * base,evutil_socket_t socket,int flags,evdns_request_callback_fn_type cb,void * user_data)17232b15cb3dSCy Schubert evdns_add_server_port_with_base(struct event_base *base, evutil_socket_t socket, int flags, evdns_request_callback_fn_type cb, void *user_data)
17242b15cb3dSCy Schubert {
17252b15cb3dSCy Schubert 	struct evdns_server_port *port;
17262b15cb3dSCy Schubert 	if (flags)
17272b15cb3dSCy Schubert 		return NULL; /* flags not yet implemented */
17282b15cb3dSCy Schubert 	if (!(port = mm_malloc(sizeof(struct evdns_server_port))))
17292b15cb3dSCy Schubert 		return NULL;
17302b15cb3dSCy Schubert 	memset(port, 0, sizeof(struct evdns_server_port));
17312b15cb3dSCy Schubert 
17322b15cb3dSCy Schubert 
17332b15cb3dSCy Schubert 	port->socket = socket;
17342b15cb3dSCy Schubert 	port->refcnt = 1;
17352b15cb3dSCy Schubert 	port->choked = 0;
17362b15cb3dSCy Schubert 	port->closing = 0;
17372b15cb3dSCy Schubert 	port->user_callback = cb;
17382b15cb3dSCy Schubert 	port->user_data = user_data;
17392b15cb3dSCy Schubert 	port->pending_replies = NULL;
17402b15cb3dSCy Schubert 	port->event_base = base;
17412b15cb3dSCy Schubert 
17422b15cb3dSCy Schubert 	event_assign(&port->event, port->event_base,
17432b15cb3dSCy Schubert 				 port->socket, EV_READ | EV_PERSIST,
17442b15cb3dSCy Schubert 				 server_port_ready_callback, port);
17452b15cb3dSCy Schubert 	if (event_add(&port->event, NULL) < 0) {
17462b15cb3dSCy Schubert 		mm_free(port);
17472b15cb3dSCy Schubert 		return NULL;
17482b15cb3dSCy Schubert 	}
17492b15cb3dSCy Schubert 	EVTHREAD_ALLOC_LOCK(port->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
17502b15cb3dSCy Schubert 	return port;
17512b15cb3dSCy Schubert }
17522b15cb3dSCy Schubert 
17532b15cb3dSCy Schubert struct evdns_server_port *
evdns_add_server_port(evutil_socket_t socket,int flags,evdns_request_callback_fn_type cb,void * user_data)17542b15cb3dSCy Schubert evdns_add_server_port(evutil_socket_t socket, int flags, evdns_request_callback_fn_type cb, void *user_data)
17552b15cb3dSCy Schubert {
17562b15cb3dSCy Schubert 	return evdns_add_server_port_with_base(NULL, socket, flags, cb, user_data);
17572b15cb3dSCy Schubert }
17582b15cb3dSCy Schubert 
17592b15cb3dSCy Schubert /* exported function */
17602b15cb3dSCy Schubert void
evdns_close_server_port(struct evdns_server_port * port)17612b15cb3dSCy Schubert evdns_close_server_port(struct evdns_server_port *port)
17622b15cb3dSCy Schubert {
17632b15cb3dSCy Schubert 	EVDNS_LOCK(port);
17642b15cb3dSCy Schubert 	if (--port->refcnt == 0) {
17652b15cb3dSCy Schubert 		EVDNS_UNLOCK(port);
17662b15cb3dSCy Schubert 		server_port_free(port);
17672b15cb3dSCy Schubert 	} else {
17682b15cb3dSCy Schubert 		port->closing = 1;
1769*a466cc55SCy Schubert 		EVDNS_UNLOCK(port);
17702b15cb3dSCy Schubert 	}
17712b15cb3dSCy Schubert }
17722b15cb3dSCy Schubert 
17732b15cb3dSCy Schubert /* exported function */
17742b15cb3dSCy Schubert int
evdns_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)17752b15cb3dSCy Schubert evdns_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)
17762b15cb3dSCy Schubert {
17772b15cb3dSCy Schubert 	struct server_request *req = TO_SERVER_REQUEST(req_);
17782b15cb3dSCy Schubert 	struct server_reply_item **itemp, *item;
17792b15cb3dSCy Schubert 	int *countp;
17802b15cb3dSCy Schubert 	int result = -1;
17812b15cb3dSCy Schubert 
17822b15cb3dSCy Schubert 	EVDNS_LOCK(req->port);
17832b15cb3dSCy Schubert 	if (req->response) /* have we already answered? */
17842b15cb3dSCy Schubert 		goto done;
17852b15cb3dSCy Schubert 
17862b15cb3dSCy Schubert 	switch (section) {
17872b15cb3dSCy Schubert 	case EVDNS_ANSWER_SECTION:
17882b15cb3dSCy Schubert 		itemp = &req->answer;
17892b15cb3dSCy Schubert 		countp = &req->n_answer;
17902b15cb3dSCy Schubert 		break;
17912b15cb3dSCy Schubert 	case EVDNS_AUTHORITY_SECTION:
17922b15cb3dSCy Schubert 		itemp = &req->authority;
17932b15cb3dSCy Schubert 		countp = &req->n_authority;
17942b15cb3dSCy Schubert 		break;
17952b15cb3dSCy Schubert 	case EVDNS_ADDITIONAL_SECTION:
17962b15cb3dSCy Schubert 		itemp = &req->additional;
17972b15cb3dSCy Schubert 		countp = &req->n_additional;
17982b15cb3dSCy Schubert 		break;
17992b15cb3dSCy Schubert 	default:
18002b15cb3dSCy Schubert 		goto done;
18012b15cb3dSCy Schubert 	}
18022b15cb3dSCy Schubert 	while (*itemp) {
18032b15cb3dSCy Schubert 		itemp = &((*itemp)->next);
18042b15cb3dSCy Schubert 	}
18052b15cb3dSCy Schubert 	item = mm_malloc(sizeof(struct server_reply_item));
18062b15cb3dSCy Schubert 	if (!item)
18072b15cb3dSCy Schubert 		goto done;
18082b15cb3dSCy Schubert 	item->next = NULL;
18092b15cb3dSCy Schubert 	if (!(item->name = mm_strdup(name))) {
18102b15cb3dSCy Schubert 		mm_free(item);
18112b15cb3dSCy Schubert 		goto done;
18122b15cb3dSCy Schubert 	}
18132b15cb3dSCy Schubert 	item->type = type;
18142b15cb3dSCy Schubert 	item->dns_question_class = class;
18152b15cb3dSCy Schubert 	item->ttl = ttl;
18162b15cb3dSCy Schubert 	item->is_name = is_name != 0;
18172b15cb3dSCy Schubert 	item->datalen = 0;
18182b15cb3dSCy Schubert 	item->data = NULL;
18192b15cb3dSCy Schubert 	if (data) {
18202b15cb3dSCy Schubert 		if (item->is_name) {
18212b15cb3dSCy Schubert 			if (!(item->data = mm_strdup(data))) {
18222b15cb3dSCy Schubert 				mm_free(item->name);
18232b15cb3dSCy Schubert 				mm_free(item);
18242b15cb3dSCy Schubert 				goto done;
18252b15cb3dSCy Schubert 			}
18262b15cb3dSCy Schubert 			item->datalen = (u16)-1;
18272b15cb3dSCy Schubert 		} else {
18282b15cb3dSCy Schubert 			if (!(item->data = mm_malloc(datalen))) {
18292b15cb3dSCy Schubert 				mm_free(item->name);
18302b15cb3dSCy Schubert 				mm_free(item);
18312b15cb3dSCy Schubert 				goto done;
18322b15cb3dSCy Schubert 			}
18332b15cb3dSCy Schubert 			item->datalen = datalen;
18342b15cb3dSCy Schubert 			memcpy(item->data, data, datalen);
18352b15cb3dSCy Schubert 		}
18362b15cb3dSCy Schubert 	}
18372b15cb3dSCy Schubert 
18382b15cb3dSCy Schubert 	*itemp = item;
18392b15cb3dSCy Schubert 	++(*countp);
18402b15cb3dSCy Schubert 	result = 0;
18412b15cb3dSCy Schubert done:
18422b15cb3dSCy Schubert 	EVDNS_UNLOCK(req->port);
18432b15cb3dSCy Schubert 	return result;
18442b15cb3dSCy Schubert }
18452b15cb3dSCy Schubert 
18462b15cb3dSCy Schubert /* exported function */
18472b15cb3dSCy Schubert int
evdns_server_request_add_a_reply(struct evdns_server_request * req,const char * name,int n,const void * addrs,int ttl)18482b15cb3dSCy Schubert evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl)
18492b15cb3dSCy Schubert {
18502b15cb3dSCy Schubert 	return evdns_server_request_add_reply(
18512b15cb3dSCy Schubert 		  req, EVDNS_ANSWER_SECTION, name, TYPE_A, CLASS_INET,
18522b15cb3dSCy Schubert 		  ttl, n*4, 0, addrs);
18532b15cb3dSCy Schubert }
18542b15cb3dSCy Schubert 
18552b15cb3dSCy Schubert /* exported function */
18562b15cb3dSCy Schubert int
evdns_server_request_add_aaaa_reply(struct evdns_server_request * req,const char * name,int n,const void * addrs,int ttl)18572b15cb3dSCy Schubert evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl)
18582b15cb3dSCy Schubert {
18592b15cb3dSCy Schubert 	return evdns_server_request_add_reply(
18602b15cb3dSCy Schubert 		  req, EVDNS_ANSWER_SECTION, name, TYPE_AAAA, CLASS_INET,
18612b15cb3dSCy Schubert 		  ttl, n*16, 0, addrs);
18622b15cb3dSCy Schubert }
18632b15cb3dSCy Schubert 
18642b15cb3dSCy Schubert /* exported function */
18652b15cb3dSCy Schubert int
evdns_server_request_add_ptr_reply(struct evdns_server_request * req,struct in_addr * in,const char * inaddr_name,const char * hostname,int ttl)18662b15cb3dSCy Schubert evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl)
18672b15cb3dSCy Schubert {
18682b15cb3dSCy Schubert 	u32 a;
18692b15cb3dSCy Schubert 	char buf[32];
18702b15cb3dSCy Schubert 	if (in && inaddr_name)
18712b15cb3dSCy Schubert 		return -1;
18722b15cb3dSCy Schubert 	else if (!in && !inaddr_name)
18732b15cb3dSCy Schubert 		return -1;
18742b15cb3dSCy Schubert 	if (in) {
18752b15cb3dSCy Schubert 		a = ntohl(in->s_addr);
18762b15cb3dSCy Schubert 		evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
18772b15cb3dSCy Schubert 				(int)(u8)((a	)&0xff),
18782b15cb3dSCy Schubert 				(int)(u8)((a>>8 )&0xff),
18792b15cb3dSCy Schubert 				(int)(u8)((a>>16)&0xff),
18802b15cb3dSCy Schubert 				(int)(u8)((a>>24)&0xff));
18812b15cb3dSCy Schubert 		inaddr_name = buf;
18822b15cb3dSCy Schubert 	}
18832b15cb3dSCy Schubert 	return evdns_server_request_add_reply(
18842b15cb3dSCy Schubert 		  req, EVDNS_ANSWER_SECTION, inaddr_name, TYPE_PTR, CLASS_INET,
18852b15cb3dSCy Schubert 		  ttl, -1, 1, hostname);
18862b15cb3dSCy Schubert }
18872b15cb3dSCy Schubert 
18882b15cb3dSCy Schubert /* exported function */
18892b15cb3dSCy Schubert int
evdns_server_request_add_cname_reply(struct evdns_server_request * req,const char * name,const char * cname,int ttl)18902b15cb3dSCy Schubert evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl)
18912b15cb3dSCy Schubert {
18922b15cb3dSCy Schubert 	return evdns_server_request_add_reply(
18932b15cb3dSCy Schubert 		  req, EVDNS_ANSWER_SECTION, name, TYPE_CNAME, CLASS_INET,
18942b15cb3dSCy Schubert 		  ttl, -1, 1, cname);
18952b15cb3dSCy Schubert }
18962b15cb3dSCy Schubert 
18972b15cb3dSCy Schubert /* exported function */
18982b15cb3dSCy Schubert void
evdns_server_request_set_flags(struct evdns_server_request * exreq,int flags)18992b15cb3dSCy Schubert evdns_server_request_set_flags(struct evdns_server_request *exreq, int flags)
19002b15cb3dSCy Schubert {
19012b15cb3dSCy Schubert 	struct server_request *req = TO_SERVER_REQUEST(exreq);
19022b15cb3dSCy Schubert 	req->base.flags &= ~(EVDNS_FLAGS_AA|EVDNS_FLAGS_RD);
19032b15cb3dSCy Schubert 	req->base.flags |= flags;
19042b15cb3dSCy Schubert }
19052b15cb3dSCy Schubert 
19062b15cb3dSCy Schubert static int
evdns_server_request_format_response(struct server_request * req,int err)19072b15cb3dSCy Schubert evdns_server_request_format_response(struct server_request *req, int err)
19082b15cb3dSCy Schubert {
19092b15cb3dSCy Schubert 	unsigned char buf[1500];
19102b15cb3dSCy Schubert 	size_t buf_len = sizeof(buf);
19112b15cb3dSCy Schubert 	off_t j = 0, r;
19122b15cb3dSCy Schubert 	u16 t_;
19132b15cb3dSCy Schubert 	u32 t32_;
19142b15cb3dSCy Schubert 	int i;
19152b15cb3dSCy Schubert 	u16 flags;
19162b15cb3dSCy Schubert 	struct dnslabel_table table;
19172b15cb3dSCy Schubert 
19182b15cb3dSCy Schubert 	if (err < 0 || err > 15) return -1;
19192b15cb3dSCy Schubert 
19202b15cb3dSCy Schubert 	/* Set response bit and error code; copy OPCODE and RD fields from
19212b15cb3dSCy Schubert 	 * question; copy RA and AA if set by caller. */
19222b15cb3dSCy Schubert 	flags = req->base.flags;
1923*a466cc55SCy Schubert 	flags |= (_QR_MASK | err);
19242b15cb3dSCy Schubert 
19252b15cb3dSCy Schubert 	dnslabel_table_init(&table);
19262b15cb3dSCy Schubert 	APPEND16(req->trans_id);
19272b15cb3dSCy Schubert 	APPEND16(flags);
19282b15cb3dSCy Schubert 	APPEND16(req->base.nquestions);
19292b15cb3dSCy Schubert 	APPEND16(req->n_answer);
19302b15cb3dSCy Schubert 	APPEND16(req->n_authority);
19312b15cb3dSCy Schubert 	APPEND16(req->n_additional);
19322b15cb3dSCy Schubert 
19332b15cb3dSCy Schubert 	/* Add questions. */
19342b15cb3dSCy Schubert 	for (i=0; i < req->base.nquestions; ++i) {
19352b15cb3dSCy Schubert 		const char *s = req->base.questions[i]->name;
19362b15cb3dSCy Schubert 		j = dnsname_to_labels(buf, buf_len, j, s, strlen(s), &table);
19372b15cb3dSCy Schubert 		if (j < 0) {
19382b15cb3dSCy Schubert 			dnslabel_clear(&table);
19392b15cb3dSCy Schubert 			return (int) j;
19402b15cb3dSCy Schubert 		}
19412b15cb3dSCy Schubert 		APPEND16(req->base.questions[i]->type);
19422b15cb3dSCy Schubert 		APPEND16(req->base.questions[i]->dns_question_class);
19432b15cb3dSCy Schubert 	}
19442b15cb3dSCy Schubert 
19452b15cb3dSCy Schubert 	/* Add answer, authority, and additional sections. */
19462b15cb3dSCy Schubert 	for (i=0; i<3; ++i) {
19472b15cb3dSCy Schubert 		struct server_reply_item *item;
19482b15cb3dSCy Schubert 		if (i==0)
19492b15cb3dSCy Schubert 			item = req->answer;
19502b15cb3dSCy Schubert 		else if (i==1)
19512b15cb3dSCy Schubert 			item = req->authority;
19522b15cb3dSCy Schubert 		else
19532b15cb3dSCy Schubert 			item = req->additional;
19542b15cb3dSCy Schubert 		while (item) {
19552b15cb3dSCy Schubert 			r = dnsname_to_labels(buf, buf_len, j, item->name, strlen(item->name), &table);
19562b15cb3dSCy Schubert 			if (r < 0)
19572b15cb3dSCy Schubert 				goto overflow;
19582b15cb3dSCy Schubert 			j = r;
19592b15cb3dSCy Schubert 
19602b15cb3dSCy Schubert 			APPEND16(item->type);
19612b15cb3dSCy Schubert 			APPEND16(item->dns_question_class);
19622b15cb3dSCy Schubert 			APPEND32(item->ttl);
19632b15cb3dSCy Schubert 			if (item->is_name) {
19642b15cb3dSCy Schubert 				off_t len_idx = j, name_start;
19652b15cb3dSCy Schubert 				j += 2;
19662b15cb3dSCy Schubert 				name_start = j;
19672b15cb3dSCy Schubert 				r = dnsname_to_labels(buf, buf_len, j, item->data, strlen(item->data), &table);
19682b15cb3dSCy Schubert 				if (r < 0)
19692b15cb3dSCy Schubert 					goto overflow;
19702b15cb3dSCy Schubert 				j = r;
19712b15cb3dSCy Schubert 				t_ = htons( (short) (j-name_start) );
19722b15cb3dSCy Schubert 				memcpy(buf+len_idx, &t_, 2);
19732b15cb3dSCy Schubert 			} else {
19742b15cb3dSCy Schubert 				APPEND16(item->datalen);
19752b15cb3dSCy Schubert 				if (j+item->datalen > (off_t)buf_len)
19762b15cb3dSCy Schubert 					goto overflow;
19772b15cb3dSCy Schubert 				memcpy(buf+j, item->data, item->datalen);
19782b15cb3dSCy Schubert 				j += item->datalen;
19792b15cb3dSCy Schubert 			}
19802b15cb3dSCy Schubert 			item = item->next;
19812b15cb3dSCy Schubert 		}
19822b15cb3dSCy Schubert 	}
19832b15cb3dSCy Schubert 
19842b15cb3dSCy Schubert 	if (j > 512) {
19852b15cb3dSCy Schubert overflow:
19862b15cb3dSCy Schubert 		j = 512;
19872b15cb3dSCy Schubert 		buf[2] |= 0x02; /* set the truncated bit. */
19882b15cb3dSCy Schubert 	}
19892b15cb3dSCy Schubert 
19902b15cb3dSCy Schubert 	req->response_len = j;
19912b15cb3dSCy Schubert 
19922b15cb3dSCy Schubert 	if (!(req->response = mm_malloc(req->response_len))) {
19932b15cb3dSCy Schubert 		server_request_free_answers(req);
19942b15cb3dSCy Schubert 		dnslabel_clear(&table);
19952b15cb3dSCy Schubert 		return (-1);
19962b15cb3dSCy Schubert 	}
19972b15cb3dSCy Schubert 	memcpy(req->response, buf, req->response_len);
19982b15cb3dSCy Schubert 	server_request_free_answers(req);
19992b15cb3dSCy Schubert 	dnslabel_clear(&table);
20002b15cb3dSCy Schubert 	return (0);
20012b15cb3dSCy Schubert }
20022b15cb3dSCy Schubert 
20032b15cb3dSCy Schubert /* exported function */
20042b15cb3dSCy Schubert int
evdns_server_request_respond(struct evdns_server_request * req_,int err)20052b15cb3dSCy Schubert evdns_server_request_respond(struct evdns_server_request *req_, int err)
20062b15cb3dSCy Schubert {
20072b15cb3dSCy Schubert 	struct server_request *req = TO_SERVER_REQUEST(req_);
20082b15cb3dSCy Schubert 	struct evdns_server_port *port = req->port;
20092b15cb3dSCy Schubert 	int r = -1;
20102b15cb3dSCy Schubert 
20112b15cb3dSCy Schubert 	EVDNS_LOCK(port);
20122b15cb3dSCy Schubert 	if (!req->response) {
20132b15cb3dSCy Schubert 		if ((r = evdns_server_request_format_response(req, err))<0)
20142b15cb3dSCy Schubert 			goto done;
20152b15cb3dSCy Schubert 	}
20162b15cb3dSCy Schubert 
20172b15cb3dSCy Schubert 	r = sendto(port->socket, req->response, (int)req->response_len, 0,
20182b15cb3dSCy Schubert 			   (struct sockaddr*) &req->addr, (ev_socklen_t)req->addrlen);
20192b15cb3dSCy Schubert 	if (r<0) {
20202b15cb3dSCy Schubert 		int sock_err = evutil_socket_geterror(port->socket);
20212b15cb3dSCy Schubert 		if (EVUTIL_ERR_RW_RETRIABLE(sock_err))
20222b15cb3dSCy Schubert 			goto done;
20232b15cb3dSCy Schubert 
20242b15cb3dSCy Schubert 		if (port->pending_replies) {
20252b15cb3dSCy Schubert 			req->prev_pending = port->pending_replies->prev_pending;
20262b15cb3dSCy Schubert 			req->next_pending = port->pending_replies;
20272b15cb3dSCy Schubert 			req->prev_pending->next_pending =
20282b15cb3dSCy Schubert 				req->next_pending->prev_pending = req;
20292b15cb3dSCy Schubert 		} else {
20302b15cb3dSCy Schubert 			req->prev_pending = req->next_pending = req;
20312b15cb3dSCy Schubert 			port->pending_replies = req;
20322b15cb3dSCy Schubert 			port->choked = 1;
20332b15cb3dSCy Schubert 
20342b15cb3dSCy Schubert 			(void) event_del(&port->event);
20352b15cb3dSCy Schubert 			event_assign(&port->event, port->event_base, port->socket, (port->closing?0:EV_READ) | EV_WRITE | EV_PERSIST, server_port_ready_callback, port);
20362b15cb3dSCy Schubert 
20372b15cb3dSCy Schubert 			if (event_add(&port->event, NULL) < 0) {
20382b15cb3dSCy Schubert 				log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server");
20392b15cb3dSCy Schubert 			}
20402b15cb3dSCy Schubert 
20412b15cb3dSCy Schubert 		}
20422b15cb3dSCy Schubert 
20432b15cb3dSCy Schubert 		r = 1;
20442b15cb3dSCy Schubert 		goto done;
20452b15cb3dSCy Schubert 	}
20462b15cb3dSCy Schubert 	if (server_request_free(req)) {
20472b15cb3dSCy Schubert 		r = 0;
20482b15cb3dSCy Schubert 		goto done;
20492b15cb3dSCy Schubert 	}
20502b15cb3dSCy Schubert 
20512b15cb3dSCy Schubert 	if (port->pending_replies)
20522b15cb3dSCy Schubert 		server_port_flush(port);
20532b15cb3dSCy Schubert 
20542b15cb3dSCy Schubert 	r = 0;
20552b15cb3dSCy Schubert done:
20562b15cb3dSCy Schubert 	EVDNS_UNLOCK(port);
20572b15cb3dSCy Schubert 	return r;
20582b15cb3dSCy Schubert }
20592b15cb3dSCy Schubert 
20602b15cb3dSCy Schubert /* Free all storage held by RRs in req. */
20612b15cb3dSCy Schubert static void
server_request_free_answers(struct server_request * req)20622b15cb3dSCy Schubert server_request_free_answers(struct server_request *req)
20632b15cb3dSCy Schubert {
20642b15cb3dSCy Schubert 	struct server_reply_item *victim, *next, **list;
20652b15cb3dSCy Schubert 	int i;
20662b15cb3dSCy Schubert 	for (i = 0; i < 3; ++i) {
20672b15cb3dSCy Schubert 		if (i==0)
20682b15cb3dSCy Schubert 			list = &req->answer;
20692b15cb3dSCy Schubert 		else if (i==1)
20702b15cb3dSCy Schubert 			list = &req->authority;
20712b15cb3dSCy Schubert 		else
20722b15cb3dSCy Schubert 			list = &req->additional;
20732b15cb3dSCy Schubert 
20742b15cb3dSCy Schubert 		victim = *list;
20752b15cb3dSCy Schubert 		while (victim) {
20762b15cb3dSCy Schubert 			next = victim->next;
20772b15cb3dSCy Schubert 			mm_free(victim->name);
20782b15cb3dSCy Schubert 			if (victim->data)
20792b15cb3dSCy Schubert 				mm_free(victim->data);
20802b15cb3dSCy Schubert 			mm_free(victim);
20812b15cb3dSCy Schubert 			victim = next;
20822b15cb3dSCy Schubert 		}
20832b15cb3dSCy Schubert 		*list = NULL;
20842b15cb3dSCy Schubert 	}
20852b15cb3dSCy Schubert }
20862b15cb3dSCy Schubert 
20872b15cb3dSCy Schubert /* Free all storage held by req, and remove links to it. */
20882b15cb3dSCy Schubert /* return true iff we just wound up freeing the server_port. */
20892b15cb3dSCy Schubert static int
server_request_free(struct server_request * req)20902b15cb3dSCy Schubert server_request_free(struct server_request *req)
20912b15cb3dSCy Schubert {
20922b15cb3dSCy Schubert 	int i, rc=1, lock=0;
20932b15cb3dSCy Schubert 	if (req->base.questions) {
20942b15cb3dSCy Schubert 		for (i = 0; i < req->base.nquestions; ++i)
20952b15cb3dSCy Schubert 			mm_free(req->base.questions[i]);
20962b15cb3dSCy Schubert 		mm_free(req->base.questions);
20972b15cb3dSCy Schubert 	}
20982b15cb3dSCy Schubert 
20992b15cb3dSCy Schubert 	if (req->port) {
21002b15cb3dSCy Schubert 		EVDNS_LOCK(req->port);
21012b15cb3dSCy Schubert 		lock=1;
21022b15cb3dSCy Schubert 		if (req->port->pending_replies == req) {
21032b15cb3dSCy Schubert 			if (req->next_pending && req->next_pending != req)
21042b15cb3dSCy Schubert 				req->port->pending_replies = req->next_pending;
21052b15cb3dSCy Schubert 			else
21062b15cb3dSCy Schubert 				req->port->pending_replies = NULL;
21072b15cb3dSCy Schubert 		}
21082b15cb3dSCy Schubert 		rc = --req->port->refcnt;
21092b15cb3dSCy Schubert 	}
21102b15cb3dSCy Schubert 
21112b15cb3dSCy Schubert 	if (req->response) {
21122b15cb3dSCy Schubert 		mm_free(req->response);
21132b15cb3dSCy Schubert 	}
21142b15cb3dSCy Schubert 
21152b15cb3dSCy Schubert 	server_request_free_answers(req);
21162b15cb3dSCy Schubert 
21172b15cb3dSCy Schubert 	if (req->next_pending && req->next_pending != req) {
21182b15cb3dSCy Schubert 		req->next_pending->prev_pending = req->prev_pending;
21192b15cb3dSCy Schubert 		req->prev_pending->next_pending = req->next_pending;
21202b15cb3dSCy Schubert 	}
21212b15cb3dSCy Schubert 
21222b15cb3dSCy Schubert 	if (rc == 0) {
21232b15cb3dSCy Schubert 		EVDNS_UNLOCK(req->port); /* ????? nickm */
21242b15cb3dSCy Schubert 		server_port_free(req->port);
21252b15cb3dSCy Schubert 		mm_free(req);
21262b15cb3dSCy Schubert 		return (1);
21272b15cb3dSCy Schubert 	}
21282b15cb3dSCy Schubert 	if (lock)
21292b15cb3dSCy Schubert 		EVDNS_UNLOCK(req->port);
21302b15cb3dSCy Schubert 	mm_free(req);
21312b15cb3dSCy Schubert 	return (0);
21322b15cb3dSCy Schubert }
21332b15cb3dSCy Schubert 
21342b15cb3dSCy Schubert /* Free all storage held by an evdns_server_port.  Only called when  */
21352b15cb3dSCy Schubert static void
server_port_free(struct evdns_server_port * port)21362b15cb3dSCy Schubert server_port_free(struct evdns_server_port *port)
21372b15cb3dSCy Schubert {
21382b15cb3dSCy Schubert 	EVUTIL_ASSERT(port);
21392b15cb3dSCy Schubert 	EVUTIL_ASSERT(!port->refcnt);
21402b15cb3dSCy Schubert 	EVUTIL_ASSERT(!port->pending_replies);
21412b15cb3dSCy Schubert 	if (port->socket > 0) {
21422b15cb3dSCy Schubert 		evutil_closesocket(port->socket);
21432b15cb3dSCy Schubert 		port->socket = -1;
21442b15cb3dSCy Schubert 	}
21452b15cb3dSCy Schubert 	(void) event_del(&port->event);
21462b15cb3dSCy Schubert 	event_debug_unassign(&port->event);
21472b15cb3dSCy Schubert 	EVTHREAD_FREE_LOCK(port->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
21482b15cb3dSCy Schubert 	mm_free(port);
21492b15cb3dSCy Schubert }
21502b15cb3dSCy Schubert 
21512b15cb3dSCy Schubert /* exported function */
21522b15cb3dSCy Schubert int
evdns_server_request_drop(struct evdns_server_request * req_)21532b15cb3dSCy Schubert evdns_server_request_drop(struct evdns_server_request *req_)
21542b15cb3dSCy Schubert {
21552b15cb3dSCy Schubert 	struct server_request *req = TO_SERVER_REQUEST(req_);
21562b15cb3dSCy Schubert 	server_request_free(req);
21572b15cb3dSCy Schubert 	return 0;
21582b15cb3dSCy Schubert }
21592b15cb3dSCy Schubert 
21602b15cb3dSCy Schubert /* exported function */
21612b15cb3dSCy Schubert int
evdns_server_request_get_requesting_addr(struct evdns_server_request * req_,struct sockaddr * sa,int addr_len)21622b15cb3dSCy Schubert evdns_server_request_get_requesting_addr(struct evdns_server_request *req_, struct sockaddr *sa, int addr_len)
21632b15cb3dSCy Schubert {
21642b15cb3dSCy Schubert 	struct server_request *req = TO_SERVER_REQUEST(req_);
21652b15cb3dSCy Schubert 	if (addr_len < (int)req->addrlen)
21662b15cb3dSCy Schubert 		return -1;
21672b15cb3dSCy Schubert 	memcpy(sa, &(req->addr), req->addrlen);
21682b15cb3dSCy Schubert 	return req->addrlen;
21692b15cb3dSCy Schubert }
21702b15cb3dSCy Schubert 
21712b15cb3dSCy Schubert #undef APPEND16
21722b15cb3dSCy Schubert #undef APPEND32
21732b15cb3dSCy Schubert 
21742b15cb3dSCy Schubert /* this is a libevent callback function which is called when a request */
21752b15cb3dSCy Schubert /* has timed out. */
21762b15cb3dSCy Schubert static void
evdns_request_timeout_callback(evutil_socket_t fd,short events,void * arg)21772b15cb3dSCy Schubert evdns_request_timeout_callback(evutil_socket_t fd, short events, void *arg) {
21782b15cb3dSCy Schubert 	struct request *const req = (struct request *) arg;
21792b15cb3dSCy Schubert 	struct evdns_base *base = req->base;
21802b15cb3dSCy Schubert 
21812b15cb3dSCy Schubert 	(void) fd;
21822b15cb3dSCy Schubert 	(void) events;
21832b15cb3dSCy Schubert 
21842b15cb3dSCy Schubert 	log(EVDNS_LOG_DEBUG, "Request %p timed out", arg);
21852b15cb3dSCy Schubert 	EVDNS_LOCK(base);
21862b15cb3dSCy Schubert 
2187a25439b6SCy Schubert 	if (req->tx_count >= req->base->global_max_retransmits) {
2188a25439b6SCy Schubert 		struct nameserver *ns = req->ns;
2189a25439b6SCy Schubert 		/* this request has failed */
2190a25439b6SCy Schubert 		log(EVDNS_LOG_DEBUG, "Giving up on request %p; tx_count==%d",
2191a25439b6SCy Schubert 		    arg, req->tx_count);
2192a25439b6SCy Schubert 		reply_schedule_callback(req, 0, DNS_ERR_TIMEOUT, NULL);
2193a25439b6SCy Schubert 
2194a25439b6SCy Schubert 		request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1);
2195a25439b6SCy Schubert 		nameserver_failed(ns, "request timed out.");
2196a25439b6SCy Schubert 	} else {
2197a25439b6SCy Schubert 		/* retransmit it */
2198a25439b6SCy Schubert 		log(EVDNS_LOG_DEBUG, "Retransmitting request %p; tx_count==%d",
2199a25439b6SCy Schubert 		    arg, req->tx_count);
2200a25439b6SCy Schubert 		(void) evtimer_del(&req->timeout_event);
2201a25439b6SCy Schubert 		request_swap_ns(req, nameserver_pick(base));
2202a25439b6SCy Schubert 		evdns_request_transmit(req);
2203a25439b6SCy Schubert 
22042b15cb3dSCy Schubert 		req->ns->timedout++;
22052b15cb3dSCy Schubert 		if (req->ns->timedout > req->base->global_max_nameserver_timeout) {
22062b15cb3dSCy Schubert 			req->ns->timedout = 0;
22072b15cb3dSCy Schubert 			nameserver_failed(req->ns, "request timed out.");
22082b15cb3dSCy Schubert 		}
22092b15cb3dSCy Schubert 	}
2210a25439b6SCy Schubert 
22112b15cb3dSCy Schubert 	EVDNS_UNLOCK(base);
22122b15cb3dSCy Schubert }
22132b15cb3dSCy Schubert 
22142b15cb3dSCy Schubert /* try to send a request to a given server. */
22152b15cb3dSCy Schubert /* */
22162b15cb3dSCy Schubert /* return: */
22172b15cb3dSCy Schubert /*   0 ok */
22182b15cb3dSCy Schubert /*   1 temporary failure */
22192b15cb3dSCy Schubert /*   2 other failure */
22202b15cb3dSCy Schubert static int
evdns_request_transmit_to(struct request * req,struct nameserver * server)22212b15cb3dSCy Schubert evdns_request_transmit_to(struct request *req, struct nameserver *server) {
22222b15cb3dSCy Schubert 	int r;
22232b15cb3dSCy Schubert 	ASSERT_LOCKED(req->base);
22242b15cb3dSCy Schubert 	ASSERT_VALID_REQUEST(req);
22252b15cb3dSCy Schubert 
22262b15cb3dSCy Schubert 	if (server->requests_inflight == 1 &&
22272b15cb3dSCy Schubert 		req->base->disable_when_inactive &&
22282b15cb3dSCy Schubert 		event_add(&server->event, NULL) < 0) {
22292b15cb3dSCy Schubert 		return 1;
22302b15cb3dSCy Schubert 	}
22312b15cb3dSCy Schubert 
22322b15cb3dSCy Schubert 	r = sendto(server->socket, (void*)req->request, req->request_len, 0,
22332b15cb3dSCy Schubert 	    (struct sockaddr *)&server->address, server->addrlen);
22342b15cb3dSCy Schubert 	if (r < 0) {
22352b15cb3dSCy Schubert 		int err = evutil_socket_geterror(server->socket);
22362b15cb3dSCy Schubert 		if (EVUTIL_ERR_RW_RETRIABLE(err))
22372b15cb3dSCy Schubert 			return 1;
22382b15cb3dSCy Schubert 		nameserver_failed(req->ns, evutil_socket_error_to_string(err));
22392b15cb3dSCy Schubert 		return 2;
22402b15cb3dSCy Schubert 	} else if (r != (int)req->request_len) {
22412b15cb3dSCy Schubert 		return 1;  /* short write */
22422b15cb3dSCy Schubert 	} else {
22432b15cb3dSCy Schubert 		return 0;
22442b15cb3dSCy Schubert 	}
22452b15cb3dSCy Schubert }
22462b15cb3dSCy Schubert 
22472b15cb3dSCy Schubert /* try to send a request, updating the fields of the request */
22482b15cb3dSCy Schubert /* as needed */
22492b15cb3dSCy Schubert /* */
22502b15cb3dSCy Schubert /* return: */
22512b15cb3dSCy Schubert /*   0 ok */
22522b15cb3dSCy Schubert /*   1 failed */
22532b15cb3dSCy Schubert static int
evdns_request_transmit(struct request * req)22542b15cb3dSCy Schubert evdns_request_transmit(struct request *req) {
22552b15cb3dSCy Schubert 	int retcode = 0, r;
22562b15cb3dSCy Schubert 
22572b15cb3dSCy Schubert 	ASSERT_LOCKED(req->base);
22582b15cb3dSCy Schubert 	ASSERT_VALID_REQUEST(req);
22592b15cb3dSCy Schubert 	/* if we fail to send this packet then this flag marks it */
22602b15cb3dSCy Schubert 	/* for evdns_transmit */
22612b15cb3dSCy Schubert 	req->transmit_me = 1;
22622b15cb3dSCy Schubert 	EVUTIL_ASSERT(req->trans_id != 0xffff);
22632b15cb3dSCy Schubert 
22642b15cb3dSCy Schubert 	if (!req->ns)
22652b15cb3dSCy Schubert 	{
22662b15cb3dSCy Schubert 		/* unable to transmit request if no nameservers */
22672b15cb3dSCy Schubert 		return 1;
22682b15cb3dSCy Schubert 	}
22692b15cb3dSCy Schubert 
22702b15cb3dSCy Schubert 	if (req->ns->choked) {
22712b15cb3dSCy Schubert 		/* don't bother trying to write to a socket */
22722b15cb3dSCy Schubert 		/* which we have had EAGAIN from */
22732b15cb3dSCy Schubert 		return 1;
22742b15cb3dSCy Schubert 	}
22752b15cb3dSCy Schubert 
22762b15cb3dSCy Schubert 	r = evdns_request_transmit_to(req, req->ns);
22772b15cb3dSCy Schubert 	switch (r) {
22782b15cb3dSCy Schubert 	case 1:
22792b15cb3dSCy Schubert 		/* temp failure */
22802b15cb3dSCy Schubert 		req->ns->choked = 1;
22812b15cb3dSCy Schubert 		nameserver_write_waiting(req->ns, 1);
22822b15cb3dSCy Schubert 		return 1;
22832b15cb3dSCy Schubert 	case 2:
2284*a466cc55SCy Schubert 		/* failed to transmit the request entirely. we can fallthrough since
2285*a466cc55SCy Schubert 		 * we'll set a timeout, which will time out, and make us retransmit the
2286*a466cc55SCy Schubert 		 * request anyway. */
22872b15cb3dSCy Schubert 		retcode = 1;
2288*a466cc55SCy Schubert 		EVUTIL_FALLTHROUGH;
22892b15cb3dSCy Schubert 	default:
22902b15cb3dSCy Schubert 		/* all ok */
22912b15cb3dSCy Schubert 		log(EVDNS_LOG_DEBUG,
22922b15cb3dSCy Schubert 		    "Setting timeout for request %p, sent to nameserver %p", req, req->ns);
22932b15cb3dSCy Schubert 		if (evtimer_add(&req->timeout_event, &req->base->global_timeout) < 0) {
22942b15cb3dSCy Schubert 			log(EVDNS_LOG_WARN,
22952b15cb3dSCy Schubert 		      "Error from libevent when adding timer for request %p",
22962b15cb3dSCy Schubert 			    req);
22972b15cb3dSCy Schubert 			/* ???? Do more? */
22982b15cb3dSCy Schubert 		}
22992b15cb3dSCy Schubert 		req->tx_count++;
23002b15cb3dSCy Schubert 		req->transmit_me = 0;
23012b15cb3dSCy Schubert 		return retcode;
23022b15cb3dSCy Schubert 	}
23032b15cb3dSCy Schubert }
23042b15cb3dSCy Schubert 
23052b15cb3dSCy Schubert static void
nameserver_probe_callback(int result,char type,int count,int ttl,void * addresses,void * arg)23062b15cb3dSCy Schubert nameserver_probe_callback(int result, char type, int count, int ttl, void *addresses, void *arg) {
23072b15cb3dSCy Schubert 	struct nameserver *const ns = (struct nameserver *) arg;
23082b15cb3dSCy Schubert 	(void) type;
23092b15cb3dSCy Schubert 	(void) count;
23102b15cb3dSCy Schubert 	(void) ttl;
23112b15cb3dSCy Schubert 	(void) addresses;
23122b15cb3dSCy Schubert 
23132b15cb3dSCy Schubert 	if (result == DNS_ERR_CANCEL) {
23142b15cb3dSCy Schubert 		/* We canceled this request because the nameserver came up
23152b15cb3dSCy Schubert 		 * for some other reason.  Do not change our opinion about
23162b15cb3dSCy Schubert 		 * the nameserver. */
23172b15cb3dSCy Schubert 		return;
23182b15cb3dSCy Schubert 	}
23192b15cb3dSCy Schubert 
23202b15cb3dSCy Schubert 	EVDNS_LOCK(ns->base);
23212b15cb3dSCy Schubert 	ns->probe_request = NULL;
23222b15cb3dSCy Schubert 	if (result == DNS_ERR_NONE || result == DNS_ERR_NOTEXIST) {
23232b15cb3dSCy Schubert 		/* this is a good reply */
23242b15cb3dSCy Schubert 		nameserver_up(ns);
23252b15cb3dSCy Schubert 	} else {
23262b15cb3dSCy Schubert 		nameserver_probe_failed(ns);
23272b15cb3dSCy Schubert 	}
23282b15cb3dSCy Schubert 	EVDNS_UNLOCK(ns->base);
23292b15cb3dSCy Schubert }
23302b15cb3dSCy Schubert 
23312b15cb3dSCy Schubert static void
nameserver_send_probe(struct nameserver * const ns)23322b15cb3dSCy Schubert nameserver_send_probe(struct nameserver *const ns) {
23332b15cb3dSCy Schubert 	struct evdns_request *handle;
23342b15cb3dSCy Schubert 	struct request *req;
23352b15cb3dSCy Schubert 	char addrbuf[128];
23362b15cb3dSCy Schubert 	/* here we need to send a probe to a given nameserver */
23372b15cb3dSCy Schubert 	/* in the hope that it is up now. */
23382b15cb3dSCy Schubert 
23392b15cb3dSCy Schubert 	ASSERT_LOCKED(ns->base);
23402b15cb3dSCy Schubert 	log(EVDNS_LOG_DEBUG, "Sending probe to %s",
23412b15cb3dSCy Schubert 	    evutil_format_sockaddr_port_(
23422b15cb3dSCy Schubert 		    (struct sockaddr *)&ns->address,
23432b15cb3dSCy Schubert 		    addrbuf, sizeof(addrbuf)));
23442b15cb3dSCy Schubert 	handle = mm_calloc(1, sizeof(*handle));
23452b15cb3dSCy Schubert 	if (!handle) return;
23462b15cb3dSCy Schubert 	req = request_new(ns->base, handle, TYPE_A, "google.com", DNS_QUERY_NO_SEARCH, nameserver_probe_callback, ns);
23472b15cb3dSCy Schubert 	if (!req) {
23482b15cb3dSCy Schubert 		mm_free(handle);
23492b15cb3dSCy Schubert 		return;
23502b15cb3dSCy Schubert 	}
23512b15cb3dSCy Schubert 	ns->probe_request = handle;
23522b15cb3dSCy Schubert 	/* we force this into the inflight queue no matter what */
23532b15cb3dSCy Schubert 	request_trans_id_set(req, transaction_id_pick(ns->base));
23542b15cb3dSCy Schubert 	req->ns = ns;
23552b15cb3dSCy Schubert 	request_submit(req);
23562b15cb3dSCy Schubert }
23572b15cb3dSCy Schubert 
23582b15cb3dSCy Schubert /* returns: */
23592b15cb3dSCy Schubert /*   0 didn't try to transmit anything */
23602b15cb3dSCy Schubert /*   1 tried to transmit something */
23612b15cb3dSCy Schubert static int
evdns_transmit(struct evdns_base * base)23622b15cb3dSCy Schubert evdns_transmit(struct evdns_base *base) {
23632b15cb3dSCy Schubert 	char did_try_to_transmit = 0;
23642b15cb3dSCy Schubert 	int i;
23652b15cb3dSCy Schubert 
23662b15cb3dSCy Schubert 	ASSERT_LOCKED(base);
23672b15cb3dSCy Schubert 	for (i = 0; i < base->n_req_heads; ++i) {
23682b15cb3dSCy Schubert 		if (base->req_heads[i]) {
23692b15cb3dSCy Schubert 			struct request *const started_at = base->req_heads[i], *req = started_at;
23702b15cb3dSCy Schubert 			/* first transmit all the requests which are currently waiting */
23712b15cb3dSCy Schubert 			do {
23722b15cb3dSCy Schubert 				if (req->transmit_me) {
23732b15cb3dSCy Schubert 					did_try_to_transmit = 1;
23742b15cb3dSCy Schubert 					evdns_request_transmit(req);
23752b15cb3dSCy Schubert 				}
23762b15cb3dSCy Schubert 
23772b15cb3dSCy Schubert 				req = req->next;
23782b15cb3dSCy Schubert 			} while (req != started_at);
23792b15cb3dSCy Schubert 		}
23802b15cb3dSCy Schubert 	}
23812b15cb3dSCy Schubert 
23822b15cb3dSCy Schubert 	return did_try_to_transmit;
23832b15cb3dSCy Schubert }
23842b15cb3dSCy Schubert 
23852b15cb3dSCy Schubert /* exported function */
23862b15cb3dSCy Schubert int
evdns_base_count_nameservers(struct evdns_base * base)23872b15cb3dSCy Schubert evdns_base_count_nameservers(struct evdns_base *base)
23882b15cb3dSCy Schubert {
23892b15cb3dSCy Schubert 	const struct nameserver *server;
23902b15cb3dSCy Schubert 	int n = 0;
23912b15cb3dSCy Schubert 
23922b15cb3dSCy Schubert 	EVDNS_LOCK(base);
23932b15cb3dSCy Schubert 	server = base->server_head;
23942b15cb3dSCy Schubert 	if (!server)
23952b15cb3dSCy Schubert 		goto done;
23962b15cb3dSCy Schubert 	do {
23972b15cb3dSCy Schubert 		++n;
23982b15cb3dSCy Schubert 		server = server->next;
23992b15cb3dSCy Schubert 	} while (server != base->server_head);
24002b15cb3dSCy Schubert done:
24012b15cb3dSCy Schubert 	EVDNS_UNLOCK(base);
24022b15cb3dSCy Schubert 	return n;
24032b15cb3dSCy Schubert }
24042b15cb3dSCy Schubert 
24052b15cb3dSCy Schubert int
evdns_count_nameservers(void)24062b15cb3dSCy Schubert evdns_count_nameservers(void)
24072b15cb3dSCy Schubert {
24082b15cb3dSCy Schubert 	return evdns_base_count_nameservers(current_base);
24092b15cb3dSCy Schubert }
24102b15cb3dSCy Schubert 
24112b15cb3dSCy Schubert /* exported function */
24122b15cb3dSCy Schubert int
evdns_base_clear_nameservers_and_suspend(struct evdns_base * base)24132b15cb3dSCy Schubert evdns_base_clear_nameservers_and_suspend(struct evdns_base *base)
24142b15cb3dSCy Schubert {
24152b15cb3dSCy Schubert 	struct nameserver *server, *started_at;
24162b15cb3dSCy Schubert 	int i;
24172b15cb3dSCy Schubert 
24182b15cb3dSCy Schubert 	EVDNS_LOCK(base);
24192b15cb3dSCy Schubert 	server = base->server_head;
24202b15cb3dSCy Schubert 	started_at = base->server_head;
24212b15cb3dSCy Schubert 	if (!server) {
24222b15cb3dSCy Schubert 		EVDNS_UNLOCK(base);
24232b15cb3dSCy Schubert 		return 0;
24242b15cb3dSCy Schubert 	}
24252b15cb3dSCy Schubert 	while (1) {
24262b15cb3dSCy Schubert 		struct nameserver *next = server->next;
24272b15cb3dSCy Schubert 		(void) event_del(&server->event);
24282b15cb3dSCy Schubert 		if (evtimer_initialized(&server->timeout_event))
24292b15cb3dSCy Schubert 			(void) evtimer_del(&server->timeout_event);
24302b15cb3dSCy Schubert 		if (server->probe_request) {
24312b15cb3dSCy Schubert 			evdns_cancel_request(server->base, server->probe_request);
24322b15cb3dSCy Schubert 			server->probe_request = NULL;
24332b15cb3dSCy Schubert 		}
24342b15cb3dSCy Schubert 		if (server->socket >= 0)
24352b15cb3dSCy Schubert 			evutil_closesocket(server->socket);
24362b15cb3dSCy Schubert 		mm_free(server);
24372b15cb3dSCy Schubert 		if (next == started_at)
24382b15cb3dSCy Schubert 			break;
24392b15cb3dSCy Schubert 		server = next;
24402b15cb3dSCy Schubert 	}
24412b15cb3dSCy Schubert 	base->server_head = NULL;
24422b15cb3dSCy Schubert 	base->global_good_nameservers = 0;
24432b15cb3dSCy Schubert 
24442b15cb3dSCy Schubert 	for (i = 0; i < base->n_req_heads; ++i) {
24452b15cb3dSCy Schubert 		struct request *req, *req_started_at;
24462b15cb3dSCy Schubert 		req = req_started_at = base->req_heads[i];
24472b15cb3dSCy Schubert 		while (req) {
24482b15cb3dSCy Schubert 			struct request *next = req->next;
24492b15cb3dSCy Schubert 			req->tx_count = req->reissue_count = 0;
24502b15cb3dSCy Schubert 			req->ns = NULL;
24512b15cb3dSCy Schubert 			/* ???? What to do about searches? */
24522b15cb3dSCy Schubert 			(void) evtimer_del(&req->timeout_event);
24532b15cb3dSCy Schubert 			req->trans_id = 0;
24542b15cb3dSCy Schubert 			req->transmit_me = 0;
24552b15cb3dSCy Schubert 
24562b15cb3dSCy Schubert 			base->global_requests_waiting++;
24572b15cb3dSCy Schubert 			evdns_request_insert(req, &base->req_waiting_head);
24582b15cb3dSCy Schubert 			/* We want to insert these suspended elements at the front of
24592b15cb3dSCy Schubert 			 * the waiting queue, since they were pending before any of
24602b15cb3dSCy Schubert 			 * the waiting entries were added.  This is a circular list,
24612b15cb3dSCy Schubert 			 * so we can just shift the start back by one.*/
24622b15cb3dSCy Schubert 			base->req_waiting_head = base->req_waiting_head->prev;
24632b15cb3dSCy Schubert 
24642b15cb3dSCy Schubert 			if (next == req_started_at)
24652b15cb3dSCy Schubert 				break;
24662b15cb3dSCy Schubert 			req = next;
24672b15cb3dSCy Schubert 		}
24682b15cb3dSCy Schubert 		base->req_heads[i] = NULL;
24692b15cb3dSCy Schubert 	}
24702b15cb3dSCy Schubert 
24712b15cb3dSCy Schubert 	base->global_requests_inflight = 0;
24722b15cb3dSCy Schubert 
24732b15cb3dSCy Schubert 	EVDNS_UNLOCK(base);
24742b15cb3dSCy Schubert 	return 0;
24752b15cb3dSCy Schubert }
24762b15cb3dSCy Schubert 
24772b15cb3dSCy Schubert int
evdns_clear_nameservers_and_suspend(void)24782b15cb3dSCy Schubert evdns_clear_nameservers_and_suspend(void)
24792b15cb3dSCy Schubert {
24802b15cb3dSCy Schubert 	return evdns_base_clear_nameservers_and_suspend(current_base);
24812b15cb3dSCy Schubert }
24822b15cb3dSCy Schubert 
24832b15cb3dSCy Schubert 
24842b15cb3dSCy Schubert /* exported function */
24852b15cb3dSCy Schubert int
evdns_base_resume(struct evdns_base * base)24862b15cb3dSCy Schubert evdns_base_resume(struct evdns_base *base)
24872b15cb3dSCy Schubert {
24882b15cb3dSCy Schubert 	EVDNS_LOCK(base);
24892b15cb3dSCy Schubert 	evdns_requests_pump_waiting_queue(base);
24902b15cb3dSCy Schubert 	EVDNS_UNLOCK(base);
24912b15cb3dSCy Schubert 
24922b15cb3dSCy Schubert 	return 0;
24932b15cb3dSCy Schubert }
24942b15cb3dSCy Schubert 
24952b15cb3dSCy Schubert int
evdns_resume(void)24962b15cb3dSCy Schubert evdns_resume(void)
24972b15cb3dSCy Schubert {
24982b15cb3dSCy Schubert 	return evdns_base_resume(current_base);
24992b15cb3dSCy Schubert }
25002b15cb3dSCy Schubert 
25012b15cb3dSCy Schubert static int
evdns_nameserver_add_impl_(struct evdns_base * base,const struct sockaddr * address,int addrlen)25022b15cb3dSCy Schubert evdns_nameserver_add_impl_(struct evdns_base *base, const struct sockaddr *address, int addrlen) {
25032b15cb3dSCy Schubert 	/* first check to see if we already have this nameserver */
25042b15cb3dSCy Schubert 
25052b15cb3dSCy Schubert 	const struct nameserver *server = base->server_head, *const started_at = base->server_head;
25062b15cb3dSCy Schubert 	struct nameserver *ns;
25072b15cb3dSCy Schubert 	int err = 0;
25082b15cb3dSCy Schubert 	char addrbuf[128];
25092b15cb3dSCy Schubert 
25102b15cb3dSCy Schubert 	ASSERT_LOCKED(base);
25112b15cb3dSCy Schubert 	if (server) {
25122b15cb3dSCy Schubert 		do {
25132b15cb3dSCy Schubert 			if (!evutil_sockaddr_cmp((struct sockaddr*)&server->address, address, 1)) return 3;
25142b15cb3dSCy Schubert 			server = server->next;
25152b15cb3dSCy Schubert 		} while (server != started_at);
25162b15cb3dSCy Schubert 	}
25172b15cb3dSCy Schubert 	if (addrlen > (int)sizeof(ns->address)) {
25182b15cb3dSCy Schubert 		log(EVDNS_LOG_DEBUG, "Addrlen %d too long.", (int)addrlen);
25192b15cb3dSCy Schubert 		return 2;
25202b15cb3dSCy Schubert 	}
25212b15cb3dSCy Schubert 
25222b15cb3dSCy Schubert 	ns = (struct nameserver *) mm_malloc(sizeof(struct nameserver));
25232b15cb3dSCy Schubert 	if (!ns) return -1;
25242b15cb3dSCy Schubert 
25252b15cb3dSCy Schubert 	memset(ns, 0, sizeof(struct nameserver));
25262b15cb3dSCy Schubert 	ns->base = base;
25272b15cb3dSCy Schubert 
25282b15cb3dSCy Schubert 	evtimer_assign(&ns->timeout_event, ns->base->event_base, nameserver_prod_callback, ns);
25292b15cb3dSCy Schubert 
25302b15cb3dSCy Schubert 	ns->socket = evutil_socket_(address->sa_family,
25312b15cb3dSCy Schubert 	    SOCK_DGRAM|EVUTIL_SOCK_NONBLOCK|EVUTIL_SOCK_CLOEXEC, 0);
25322b15cb3dSCy Schubert 	if (ns->socket < 0) { err = 1; goto out1; }
25332b15cb3dSCy Schubert 
25342b15cb3dSCy Schubert 	if (base->global_outgoing_addrlen &&
25352b15cb3dSCy Schubert 	    !evutil_sockaddr_is_loopback_(address)) {
25362b15cb3dSCy Schubert 		if (bind(ns->socket,
25372b15cb3dSCy Schubert 			(struct sockaddr*)&base->global_outgoing_address,
25382b15cb3dSCy Schubert 			base->global_outgoing_addrlen) < 0) {
25392b15cb3dSCy Schubert 			log(EVDNS_LOG_WARN,"Couldn't bind to outgoing address");
25402b15cb3dSCy Schubert 			err = 2;
25412b15cb3dSCy Schubert 			goto out2;
25422b15cb3dSCy Schubert 		}
25432b15cb3dSCy Schubert 	}
25442b15cb3dSCy Schubert 
2545*a466cc55SCy Schubert 	if (base->so_rcvbuf) {
2546*a466cc55SCy Schubert 		if (setsockopt(ns->socket, SOL_SOCKET, SO_RCVBUF,
2547*a466cc55SCy Schubert 		    (void *)&base->so_rcvbuf, sizeof(base->so_rcvbuf))) {
2548*a466cc55SCy Schubert 			log(EVDNS_LOG_WARN, "Couldn't set SO_RCVBUF to %i", base->so_rcvbuf);
2549*a466cc55SCy Schubert 			err = -SO_RCVBUF;
2550*a466cc55SCy Schubert 			goto out2;
2551*a466cc55SCy Schubert 		}
2552*a466cc55SCy Schubert 	}
2553*a466cc55SCy Schubert 	if (base->so_sndbuf) {
2554*a466cc55SCy Schubert 		if (setsockopt(ns->socket, SOL_SOCKET, SO_SNDBUF,
2555*a466cc55SCy Schubert 		    (void *)&base->so_sndbuf, sizeof(base->so_sndbuf))) {
2556*a466cc55SCy Schubert 			log(EVDNS_LOG_WARN, "Couldn't set SO_SNDBUF to %i", base->so_sndbuf);
2557*a466cc55SCy Schubert 			err = -SO_SNDBUF;
2558*a466cc55SCy Schubert 			goto out2;
2559*a466cc55SCy Schubert 		}
2560*a466cc55SCy Schubert 	}
2561*a466cc55SCy Schubert 
25622b15cb3dSCy Schubert 	memcpy(&ns->address, address, addrlen);
25632b15cb3dSCy Schubert 	ns->addrlen = addrlen;
25642b15cb3dSCy Schubert 	ns->state = 1;
25652b15cb3dSCy Schubert 	event_assign(&ns->event, ns->base->event_base, ns->socket,
25662b15cb3dSCy Schubert 				 EV_READ | EV_PERSIST, nameserver_ready_callback, ns);
25672b15cb3dSCy Schubert 	if (!base->disable_when_inactive && event_add(&ns->event, NULL) < 0) {
25682b15cb3dSCy Schubert 		err = 2;
25692b15cb3dSCy Schubert 		goto out2;
25702b15cb3dSCy Schubert 	}
25712b15cb3dSCy Schubert 
25722b15cb3dSCy Schubert 	log(EVDNS_LOG_DEBUG, "Added nameserver %s as %p",
25732b15cb3dSCy Schubert 	    evutil_format_sockaddr_port_(address, addrbuf, sizeof(addrbuf)), ns);
25742b15cb3dSCy Schubert 
25752b15cb3dSCy Schubert 	/* insert this nameserver into the list of them */
25762b15cb3dSCy Schubert 	if (!base->server_head) {
25772b15cb3dSCy Schubert 		ns->next = ns->prev = ns;
25782b15cb3dSCy Schubert 		base->server_head = ns;
25792b15cb3dSCy Schubert 	} else {
25802b15cb3dSCy Schubert 		ns->next = base->server_head->next;
25812b15cb3dSCy Schubert 		ns->prev = base->server_head;
25822b15cb3dSCy Schubert 		base->server_head->next = ns;
25832b15cb3dSCy Schubert 		ns->next->prev = ns;
25842b15cb3dSCy Schubert 	}
25852b15cb3dSCy Schubert 
25862b15cb3dSCy Schubert 	base->global_good_nameservers++;
25872b15cb3dSCy Schubert 
25882b15cb3dSCy Schubert 	return 0;
25892b15cb3dSCy Schubert 
25902b15cb3dSCy Schubert out2:
25912b15cb3dSCy Schubert 	evutil_closesocket(ns->socket);
25922b15cb3dSCy Schubert out1:
25932b15cb3dSCy Schubert 	event_debug_unassign(&ns->event);
25942b15cb3dSCy Schubert 	mm_free(ns);
25952b15cb3dSCy Schubert 	log(EVDNS_LOG_WARN, "Unable to add nameserver %s: error %d",
25962b15cb3dSCy Schubert 	    evutil_format_sockaddr_port_(address, addrbuf, sizeof(addrbuf)), err);
25972b15cb3dSCy Schubert 	return err;
25982b15cb3dSCy Schubert }
25992b15cb3dSCy Schubert 
26002b15cb3dSCy Schubert /* exported function */
26012b15cb3dSCy Schubert int
evdns_base_nameserver_add(struct evdns_base * base,unsigned long int address)26022b15cb3dSCy Schubert evdns_base_nameserver_add(struct evdns_base *base, unsigned long int address)
26032b15cb3dSCy Schubert {
26042b15cb3dSCy Schubert 	struct sockaddr_in sin;
26052b15cb3dSCy Schubert 	int res;
26062b15cb3dSCy Schubert 	memset(&sin, 0, sizeof(sin));
26072b15cb3dSCy Schubert 	sin.sin_addr.s_addr = address;
26082b15cb3dSCy Schubert 	sin.sin_port = htons(53);
26092b15cb3dSCy Schubert 	sin.sin_family = AF_INET;
26102b15cb3dSCy Schubert 	EVDNS_LOCK(base);
26112b15cb3dSCy Schubert 	res = evdns_nameserver_add_impl_(base, (struct sockaddr*)&sin, sizeof(sin));
26122b15cb3dSCy Schubert 	EVDNS_UNLOCK(base);
26132b15cb3dSCy Schubert 	return res;
26142b15cb3dSCy Schubert }
26152b15cb3dSCy Schubert 
26162b15cb3dSCy Schubert int
evdns_nameserver_add(unsigned long int address)26172b15cb3dSCy Schubert evdns_nameserver_add(unsigned long int address) {
26182b15cb3dSCy Schubert 	if (!current_base)
26192b15cb3dSCy Schubert 		current_base = evdns_base_new(NULL, 0);
26202b15cb3dSCy Schubert 	return evdns_base_nameserver_add(current_base, address);
26212b15cb3dSCy Schubert }
26222b15cb3dSCy Schubert 
26232b15cb3dSCy Schubert static void
sockaddr_setport(struct sockaddr * sa,ev_uint16_t port)26242b15cb3dSCy Schubert sockaddr_setport(struct sockaddr *sa, ev_uint16_t port)
26252b15cb3dSCy Schubert {
26262b15cb3dSCy Schubert 	if (sa->sa_family == AF_INET) {
26272b15cb3dSCy Schubert 		((struct sockaddr_in *)sa)->sin_port = htons(port);
26282b15cb3dSCy Schubert 	} else if (sa->sa_family == AF_INET6) {
26292b15cb3dSCy Schubert 		((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
26302b15cb3dSCy Schubert 	}
26312b15cb3dSCy Schubert }
26322b15cb3dSCy Schubert 
26332b15cb3dSCy Schubert static ev_uint16_t
sockaddr_getport(struct sockaddr * sa)26342b15cb3dSCy Schubert sockaddr_getport(struct sockaddr *sa)
26352b15cb3dSCy Schubert {
26362b15cb3dSCy Schubert 	if (sa->sa_family == AF_INET) {
26372b15cb3dSCy Schubert 		return ntohs(((struct sockaddr_in *)sa)->sin_port);
26382b15cb3dSCy Schubert 	} else if (sa->sa_family == AF_INET6) {
26392b15cb3dSCy Schubert 		return ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
26402b15cb3dSCy Schubert 	} else {
26412b15cb3dSCy Schubert 		return 0;
26422b15cb3dSCy Schubert 	}
26432b15cb3dSCy Schubert }
26442b15cb3dSCy Schubert 
26452b15cb3dSCy Schubert /* exported function */
26462b15cb3dSCy Schubert int
evdns_base_nameserver_ip_add(struct evdns_base * base,const char * ip_as_string)26472b15cb3dSCy Schubert evdns_base_nameserver_ip_add(struct evdns_base *base, const char *ip_as_string) {
26482b15cb3dSCy Schubert 	struct sockaddr_storage ss;
26492b15cb3dSCy Schubert 	struct sockaddr *sa;
26502b15cb3dSCy Schubert 	int len = sizeof(ss);
26512b15cb3dSCy Schubert 	int res;
26522b15cb3dSCy Schubert 	if (evutil_parse_sockaddr_port(ip_as_string, (struct sockaddr *)&ss,
26532b15cb3dSCy Schubert 		&len)) {
26542b15cb3dSCy Schubert 		log(EVDNS_LOG_WARN, "Unable to parse nameserver address %s",
26552b15cb3dSCy Schubert 			ip_as_string);
26562b15cb3dSCy Schubert 		return 4;
26572b15cb3dSCy Schubert 	}
26582b15cb3dSCy Schubert 	sa = (struct sockaddr *) &ss;
26592b15cb3dSCy Schubert 	if (sockaddr_getport(sa) == 0)
26602b15cb3dSCy Schubert 		sockaddr_setport(sa, 53);
26612b15cb3dSCy Schubert 
26622b15cb3dSCy Schubert 	EVDNS_LOCK(base);
26632b15cb3dSCy Schubert 	res = evdns_nameserver_add_impl_(base, sa, len);
26642b15cb3dSCy Schubert 	EVDNS_UNLOCK(base);
26652b15cb3dSCy Schubert 	return res;
26662b15cb3dSCy Schubert }
26672b15cb3dSCy Schubert 
26682b15cb3dSCy Schubert int
evdns_nameserver_ip_add(const char * ip_as_string)26692b15cb3dSCy Schubert evdns_nameserver_ip_add(const char *ip_as_string) {
26702b15cb3dSCy Schubert 	if (!current_base)
26712b15cb3dSCy Schubert 		current_base = evdns_base_new(NULL, 0);
26722b15cb3dSCy Schubert 	return evdns_base_nameserver_ip_add(current_base, ip_as_string);
26732b15cb3dSCy Schubert }
26742b15cb3dSCy Schubert 
26752b15cb3dSCy Schubert int
evdns_base_nameserver_sockaddr_add(struct evdns_base * base,const struct sockaddr * sa,ev_socklen_t len,unsigned flags)26762b15cb3dSCy Schubert evdns_base_nameserver_sockaddr_add(struct evdns_base *base,
26772b15cb3dSCy Schubert     const struct sockaddr *sa, ev_socklen_t len, unsigned flags)
26782b15cb3dSCy Schubert {
26792b15cb3dSCy Schubert 	int res;
26802b15cb3dSCy Schubert 	EVUTIL_ASSERT(base);
26812b15cb3dSCy Schubert 	EVDNS_LOCK(base);
26822b15cb3dSCy Schubert 	res = evdns_nameserver_add_impl_(base, sa, len);
26832b15cb3dSCy Schubert 	EVDNS_UNLOCK(base);
26842b15cb3dSCy Schubert 	return res;
26852b15cb3dSCy Schubert }
26862b15cb3dSCy Schubert 
2687a25439b6SCy Schubert int
evdns_base_get_nameserver_addr(struct evdns_base * base,int idx,struct sockaddr * sa,ev_socklen_t len)2688a25439b6SCy Schubert evdns_base_get_nameserver_addr(struct evdns_base *base, int idx,
2689a25439b6SCy Schubert     struct sockaddr *sa, ev_socklen_t len)
2690a25439b6SCy Schubert {
2691a25439b6SCy Schubert 	int result = -1;
2692a25439b6SCy Schubert 	int i;
2693a25439b6SCy Schubert 	struct nameserver *server;
2694a25439b6SCy Schubert 	EVDNS_LOCK(base);
2695a25439b6SCy Schubert 	server = base->server_head;
2696a25439b6SCy Schubert 	for (i = 0; i < idx && server; ++i, server = server->next) {
2697a25439b6SCy Schubert 		if (server->next == base->server_head)
2698a25439b6SCy Schubert 			goto done;
2699a25439b6SCy Schubert 	}
2700a25439b6SCy Schubert 	if (! server)
2701a25439b6SCy Schubert 		goto done;
2702a25439b6SCy Schubert 
2703a25439b6SCy Schubert 	if (server->addrlen > len) {
2704a25439b6SCy Schubert 		result = (int) server->addrlen;
2705a25439b6SCy Schubert 		goto done;
2706a25439b6SCy Schubert 	}
2707a25439b6SCy Schubert 
2708a25439b6SCy Schubert 	memcpy(sa, &server->address, server->addrlen);
2709a25439b6SCy Schubert 	result = (int) server->addrlen;
2710a25439b6SCy Schubert done:
2711a25439b6SCy Schubert 	EVDNS_UNLOCK(base);
2712a25439b6SCy Schubert 	return result;
2713a25439b6SCy Schubert }
2714a25439b6SCy Schubert 
27152b15cb3dSCy Schubert /* remove from the queue */
27162b15cb3dSCy Schubert static void
evdns_request_remove(struct request * req,struct request ** head)27172b15cb3dSCy Schubert evdns_request_remove(struct request *req, struct request **head)
27182b15cb3dSCy Schubert {
27192b15cb3dSCy Schubert 	ASSERT_LOCKED(req->base);
27202b15cb3dSCy Schubert 	ASSERT_VALID_REQUEST(req);
27212b15cb3dSCy Schubert 
27222b15cb3dSCy Schubert #if 0
27232b15cb3dSCy Schubert 	{
27242b15cb3dSCy Schubert 		struct request *ptr;
27252b15cb3dSCy Schubert 		int found = 0;
27262b15cb3dSCy Schubert 		EVUTIL_ASSERT(*head != NULL);
27272b15cb3dSCy Schubert 
27282b15cb3dSCy Schubert 		ptr = *head;
27292b15cb3dSCy Schubert 		do {
27302b15cb3dSCy Schubert 			if (ptr == req) {
27312b15cb3dSCy Schubert 				found = 1;
27322b15cb3dSCy Schubert 				break;
27332b15cb3dSCy Schubert 			}
27342b15cb3dSCy Schubert 			ptr = ptr->next;
27352b15cb3dSCy Schubert 		} while (ptr != *head);
27362b15cb3dSCy Schubert 		EVUTIL_ASSERT(found);
27372b15cb3dSCy Schubert 
27382b15cb3dSCy Schubert 		EVUTIL_ASSERT(req->next);
27392b15cb3dSCy Schubert 	}
27402b15cb3dSCy Schubert #endif
27412b15cb3dSCy Schubert 
27422b15cb3dSCy Schubert 	if (req->next == req) {
27432b15cb3dSCy Schubert 		/* only item in the list */
27442b15cb3dSCy Schubert 		*head = NULL;
27452b15cb3dSCy Schubert 	} else {
27462b15cb3dSCy Schubert 		req->next->prev = req->prev;
27472b15cb3dSCy Schubert 		req->prev->next = req->next;
27482b15cb3dSCy Schubert 		if (*head == req) *head = req->next;
27492b15cb3dSCy Schubert 	}
27502b15cb3dSCy Schubert 	req->next = req->prev = NULL;
27512b15cb3dSCy Schubert }
27522b15cb3dSCy Schubert 
27532b15cb3dSCy Schubert /* insert into the tail of the queue */
27542b15cb3dSCy Schubert static void
evdns_request_insert(struct request * req,struct request ** head)27552b15cb3dSCy Schubert evdns_request_insert(struct request *req, struct request **head) {
27562b15cb3dSCy Schubert 	ASSERT_LOCKED(req->base);
27572b15cb3dSCy Schubert 	ASSERT_VALID_REQUEST(req);
27582b15cb3dSCy Schubert 	if (!*head) {
27592b15cb3dSCy Schubert 		*head = req;
27602b15cb3dSCy Schubert 		req->next = req->prev = req;
27612b15cb3dSCy Schubert 		return;
27622b15cb3dSCy Schubert 	}
27632b15cb3dSCy Schubert 
27642b15cb3dSCy Schubert 	req->prev = (*head)->prev;
27652b15cb3dSCy Schubert 	req->prev->next = req;
27662b15cb3dSCy Schubert 	req->next = *head;
27672b15cb3dSCy Schubert 	(*head)->prev = req;
27682b15cb3dSCy Schubert }
27692b15cb3dSCy Schubert 
27702b15cb3dSCy Schubert static int
string_num_dots(const char * s)27712b15cb3dSCy Schubert string_num_dots(const char *s) {
27722b15cb3dSCy Schubert 	int count = 0;
27732b15cb3dSCy Schubert 	while ((s = strchr(s, '.'))) {
27742b15cb3dSCy Schubert 		s++;
27752b15cb3dSCy Schubert 		count++;
27762b15cb3dSCy Schubert 	}
27772b15cb3dSCy Schubert 	return count;
27782b15cb3dSCy Schubert }
27792b15cb3dSCy Schubert 
27802b15cb3dSCy Schubert static struct request *
request_new(struct evdns_base * base,struct evdns_request * handle,int type,const char * name,int flags,evdns_callback_type callback,void * user_ptr)27812b15cb3dSCy Schubert request_new(struct evdns_base *base, struct evdns_request *handle, int type,
27822b15cb3dSCy Schubert 	    const char *name, int flags, evdns_callback_type callback,
27832b15cb3dSCy Schubert 	    void *user_ptr) {
27842b15cb3dSCy Schubert 
27852b15cb3dSCy Schubert 	const char issuing_now =
27862b15cb3dSCy Schubert 	    (base->global_requests_inflight < base->global_max_requests_inflight) ? 1 : 0;
27872b15cb3dSCy Schubert 
27882b15cb3dSCy Schubert 	const size_t name_len = strlen(name);
27892b15cb3dSCy Schubert 	const size_t request_max_len = evdns_request_len(name_len);
27902b15cb3dSCy Schubert 	const u16 trans_id = issuing_now ? transaction_id_pick(base) : 0xffff;
27912b15cb3dSCy Schubert 	/* the request data is alloced in a single block with the header */
27922b15cb3dSCy Schubert 	struct request *const req =
27932b15cb3dSCy Schubert 	    mm_malloc(sizeof(struct request) + request_max_len);
27942b15cb3dSCy Schubert 	int rlen;
27952b15cb3dSCy Schubert 	char namebuf[256];
27962b15cb3dSCy Schubert 	(void) flags;
27972b15cb3dSCy Schubert 
27982b15cb3dSCy Schubert 	ASSERT_LOCKED(base);
27992b15cb3dSCy Schubert 
28002b15cb3dSCy Schubert 	if (!req) return NULL;
28012b15cb3dSCy Schubert 
28022b15cb3dSCy Schubert 	if (name_len >= sizeof(namebuf)) {
28032b15cb3dSCy Schubert 		mm_free(req);
28042b15cb3dSCy Schubert 		return NULL;
28052b15cb3dSCy Schubert 	}
28062b15cb3dSCy Schubert 
28072b15cb3dSCy Schubert 	memset(req, 0, sizeof(struct request));
28082b15cb3dSCy Schubert 	req->base = base;
28092b15cb3dSCy Schubert 
28102b15cb3dSCy Schubert 	evtimer_assign(&req->timeout_event, req->base->event_base, evdns_request_timeout_callback, req);
28112b15cb3dSCy Schubert 
28122b15cb3dSCy Schubert 	if (base->global_randomize_case) {
28132b15cb3dSCy Schubert 		unsigned i;
28142b15cb3dSCy Schubert 		char randbits[(sizeof(namebuf)+7)/8];
28152b15cb3dSCy Schubert 		strlcpy(namebuf, name, sizeof(namebuf));
28162b15cb3dSCy Schubert 		evutil_secure_rng_get_bytes(randbits, (name_len+7)/8);
28172b15cb3dSCy Schubert 		for (i = 0; i < name_len; ++i) {
28182b15cb3dSCy Schubert 			if (EVUTIL_ISALPHA_(namebuf[i])) {
28192b15cb3dSCy Schubert 				if ((randbits[i >> 3] & (1<<(i & 7))))
28202b15cb3dSCy Schubert 					namebuf[i] |= 0x20;
28212b15cb3dSCy Schubert 				else
28222b15cb3dSCy Schubert 					namebuf[i] &= ~0x20;
28232b15cb3dSCy Schubert 			}
28242b15cb3dSCy Schubert 		}
28252b15cb3dSCy Schubert 		name = namebuf;
28262b15cb3dSCy Schubert 	}
28272b15cb3dSCy Schubert 
28282b15cb3dSCy Schubert 	/* request data lives just after the header */
28292b15cb3dSCy Schubert 	req->request = ((u8 *) req) + sizeof(struct request);
28302b15cb3dSCy Schubert 	/* denotes that the request data shouldn't be free()ed */
28312b15cb3dSCy Schubert 	req->request_appended = 1;
28322b15cb3dSCy Schubert 	rlen = evdns_request_data_build(name, name_len, trans_id,
28332b15cb3dSCy Schubert 	    type, CLASS_INET, req->request, request_max_len);
28342b15cb3dSCy Schubert 	if (rlen < 0)
28352b15cb3dSCy Schubert 		goto err1;
28362b15cb3dSCy Schubert 
28372b15cb3dSCy Schubert 	req->request_len = rlen;
28382b15cb3dSCy Schubert 	req->trans_id = trans_id;
28392b15cb3dSCy Schubert 	req->tx_count = 0;
28402b15cb3dSCy Schubert 	req->request_type = type;
28412b15cb3dSCy Schubert 	req->user_pointer = user_ptr;
28422b15cb3dSCy Schubert 	req->user_callback = callback;
28432b15cb3dSCy Schubert 	req->ns = issuing_now ? nameserver_pick(base) : NULL;
28442b15cb3dSCy Schubert 	req->next = req->prev = NULL;
28452b15cb3dSCy Schubert 	req->handle = handle;
28462b15cb3dSCy Schubert 	if (handle) {
28472b15cb3dSCy Schubert 		handle->current_req = req;
28482b15cb3dSCy Schubert 		handle->base = base;
28492b15cb3dSCy Schubert 	}
28502b15cb3dSCy Schubert 
28512b15cb3dSCy Schubert 	return req;
28522b15cb3dSCy Schubert err1:
28532b15cb3dSCy Schubert 	mm_free(req);
28542b15cb3dSCy Schubert 	return NULL;
28552b15cb3dSCy Schubert }
28562b15cb3dSCy Schubert 
28572b15cb3dSCy Schubert static void
request_submit(struct request * const req)28582b15cb3dSCy Schubert request_submit(struct request *const req) {
28592b15cb3dSCy Schubert 	struct evdns_base *base = req->base;
28602b15cb3dSCy Schubert 	ASSERT_LOCKED(base);
28612b15cb3dSCy Schubert 	ASSERT_VALID_REQUEST(req);
28622b15cb3dSCy Schubert 	if (req->ns) {
28632b15cb3dSCy Schubert 		/* if it has a nameserver assigned then this is going */
28642b15cb3dSCy Schubert 		/* straight into the inflight queue */
28652b15cb3dSCy Schubert 		evdns_request_insert(req, &REQ_HEAD(base, req->trans_id));
28662b15cb3dSCy Schubert 
28672b15cb3dSCy Schubert 		base->global_requests_inflight++;
28682b15cb3dSCy Schubert 		req->ns->requests_inflight++;
28692b15cb3dSCy Schubert 
28702b15cb3dSCy Schubert 		evdns_request_transmit(req);
28712b15cb3dSCy Schubert 	} else {
28722b15cb3dSCy Schubert 		evdns_request_insert(req, &base->req_waiting_head);
28732b15cb3dSCy Schubert 		base->global_requests_waiting++;
28742b15cb3dSCy Schubert 	}
28752b15cb3dSCy Schubert }
28762b15cb3dSCy Schubert 
28772b15cb3dSCy Schubert /* exported function */
28782b15cb3dSCy Schubert void
evdns_cancel_request(struct evdns_base * base,struct evdns_request * handle)28792b15cb3dSCy Schubert evdns_cancel_request(struct evdns_base *base, struct evdns_request *handle)
28802b15cb3dSCy Schubert {
28812b15cb3dSCy Schubert 	struct request *req;
28822b15cb3dSCy Schubert 
28832b15cb3dSCy Schubert 	if (!handle->current_req)
28842b15cb3dSCy Schubert 		return;
28852b15cb3dSCy Schubert 
28862b15cb3dSCy Schubert 	if (!base) {
28872b15cb3dSCy Schubert 		/* This redundancy is silly; can we fix it? (Not for 2.0) XXXX */
28882b15cb3dSCy Schubert 		base = handle->base;
28892b15cb3dSCy Schubert 		if (!base)
28902b15cb3dSCy Schubert 			base = handle->current_req->base;
28912b15cb3dSCy Schubert 	}
28922b15cb3dSCy Schubert 
28932b15cb3dSCy Schubert 	EVDNS_LOCK(base);
28942b15cb3dSCy Schubert 	if (handle->pending_cb) {
28952b15cb3dSCy Schubert 		EVDNS_UNLOCK(base);
28962b15cb3dSCy Schubert 		return;
28972b15cb3dSCy Schubert 	}
28982b15cb3dSCy Schubert 
28992b15cb3dSCy Schubert 	req = handle->current_req;
29002b15cb3dSCy Schubert 	ASSERT_VALID_REQUEST(req);
29012b15cb3dSCy Schubert 
29022b15cb3dSCy Schubert 	reply_schedule_callback(req, 0, DNS_ERR_CANCEL, NULL);
29032b15cb3dSCy Schubert 	if (req->ns) {
29042b15cb3dSCy Schubert 		/* remove from inflight queue */
29052b15cb3dSCy Schubert 		request_finished(req, &REQ_HEAD(base, req->trans_id), 1);
29062b15cb3dSCy Schubert 	} else {
29072b15cb3dSCy Schubert 		/* remove from global_waiting head */
29082b15cb3dSCy Schubert 		request_finished(req, &base->req_waiting_head, 1);
29092b15cb3dSCy Schubert 	}
29102b15cb3dSCy Schubert 	EVDNS_UNLOCK(base);
29112b15cb3dSCy Schubert }
29122b15cb3dSCy Schubert 
29132b15cb3dSCy Schubert /* exported function */
29142b15cb3dSCy Schubert struct evdns_request *
evdns_base_resolve_ipv4(struct evdns_base * base,const char * name,int flags,evdns_callback_type callback,void * ptr)29152b15cb3dSCy Schubert evdns_base_resolve_ipv4(struct evdns_base *base, const char *name, int flags,
29162b15cb3dSCy Schubert     evdns_callback_type callback, void *ptr) {
29172b15cb3dSCy Schubert 	struct evdns_request *handle;
29182b15cb3dSCy Schubert 	struct request *req;
29192b15cb3dSCy Schubert 	log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
29202b15cb3dSCy Schubert 	handle = mm_calloc(1, sizeof(*handle));
29212b15cb3dSCy Schubert 	if (handle == NULL)
29222b15cb3dSCy Schubert 		return NULL;
29232b15cb3dSCy Schubert 	EVDNS_LOCK(base);
29242b15cb3dSCy Schubert 	if (flags & DNS_QUERY_NO_SEARCH) {
29252b15cb3dSCy Schubert 		req =
29262b15cb3dSCy Schubert 			request_new(base, handle, TYPE_A, name, flags,
29272b15cb3dSCy Schubert 				    callback, ptr);
29282b15cb3dSCy Schubert 		if (req)
29292b15cb3dSCy Schubert 			request_submit(req);
29302b15cb3dSCy Schubert 	} else {
29312b15cb3dSCy Schubert 		search_request_new(base, handle, TYPE_A, name, flags,
29322b15cb3dSCy Schubert 		    callback, ptr);
29332b15cb3dSCy Schubert 	}
29342b15cb3dSCy Schubert 	if (handle->current_req == NULL) {
29352b15cb3dSCy Schubert 		mm_free(handle);
29362b15cb3dSCy Schubert 		handle = NULL;
29372b15cb3dSCy Schubert 	}
29382b15cb3dSCy Schubert 	EVDNS_UNLOCK(base);
29392b15cb3dSCy Schubert 	return handle;
29402b15cb3dSCy Schubert }
29412b15cb3dSCy Schubert 
evdns_resolve_ipv4(const char * name,int flags,evdns_callback_type callback,void * ptr)29422b15cb3dSCy Schubert int evdns_resolve_ipv4(const char *name, int flags,
29432b15cb3dSCy Schubert 					   evdns_callback_type callback, void *ptr)
29442b15cb3dSCy Schubert {
29452b15cb3dSCy Schubert 	return evdns_base_resolve_ipv4(current_base, name, flags, callback, ptr)
29462b15cb3dSCy Schubert 		? 0 : -1;
29472b15cb3dSCy Schubert }
29482b15cb3dSCy Schubert 
29492b15cb3dSCy Schubert 
29502b15cb3dSCy Schubert /* exported function */
29512b15cb3dSCy Schubert struct evdns_request *
evdns_base_resolve_ipv6(struct evdns_base * base,const char * name,int flags,evdns_callback_type callback,void * ptr)29522b15cb3dSCy Schubert evdns_base_resolve_ipv6(struct evdns_base *base,
29532b15cb3dSCy Schubert     const char *name, int flags,
29542b15cb3dSCy Schubert     evdns_callback_type callback, void *ptr)
29552b15cb3dSCy Schubert {
29562b15cb3dSCy Schubert 	struct evdns_request *handle;
29572b15cb3dSCy Schubert 	struct request *req;
29582b15cb3dSCy Schubert 	log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
29592b15cb3dSCy Schubert 	handle = mm_calloc(1, sizeof(*handle));
29602b15cb3dSCy Schubert 	if (handle == NULL)
29612b15cb3dSCy Schubert 		return NULL;
29622b15cb3dSCy Schubert 	EVDNS_LOCK(base);
29632b15cb3dSCy Schubert 	if (flags & DNS_QUERY_NO_SEARCH) {
29642b15cb3dSCy Schubert 		req = request_new(base, handle, TYPE_AAAA, name, flags,
29652b15cb3dSCy Schubert 				  callback, ptr);
29662b15cb3dSCy Schubert 		if (req)
29672b15cb3dSCy Schubert 			request_submit(req);
29682b15cb3dSCy Schubert 	} else {
29692b15cb3dSCy Schubert 		search_request_new(base, handle, TYPE_AAAA, name, flags,
29702b15cb3dSCy Schubert 		    callback, ptr);
29712b15cb3dSCy Schubert 	}
29722b15cb3dSCy Schubert 	if (handle->current_req == NULL) {
29732b15cb3dSCy Schubert 		mm_free(handle);
29742b15cb3dSCy Schubert 		handle = NULL;
29752b15cb3dSCy Schubert 	}
29762b15cb3dSCy Schubert 	EVDNS_UNLOCK(base);
29772b15cb3dSCy Schubert 	return handle;
29782b15cb3dSCy Schubert }
29792b15cb3dSCy Schubert 
evdns_resolve_ipv6(const char * name,int flags,evdns_callback_type callback,void * ptr)29802b15cb3dSCy Schubert int evdns_resolve_ipv6(const char *name, int flags,
29812b15cb3dSCy Schubert     evdns_callback_type callback, void *ptr) {
29822b15cb3dSCy Schubert 	return evdns_base_resolve_ipv6(current_base, name, flags, callback, ptr)
29832b15cb3dSCy Schubert 		? 0 : -1;
29842b15cb3dSCy Schubert }
29852b15cb3dSCy Schubert 
29862b15cb3dSCy Schubert struct evdns_request *
evdns_base_resolve_reverse(struct evdns_base * base,const struct in_addr * in,int flags,evdns_callback_type callback,void * ptr)29872b15cb3dSCy Schubert evdns_base_resolve_reverse(struct evdns_base *base, const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) {
29882b15cb3dSCy Schubert 	char buf[32];
29892b15cb3dSCy Schubert 	struct evdns_request *handle;
29902b15cb3dSCy Schubert 	struct request *req;
29912b15cb3dSCy Schubert 	u32 a;
29922b15cb3dSCy Schubert 	EVUTIL_ASSERT(in);
29932b15cb3dSCy Schubert 	a = ntohl(in->s_addr);
29942b15cb3dSCy Schubert 	evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
29952b15cb3dSCy Schubert 			(int)(u8)((a	)&0xff),
29962b15cb3dSCy Schubert 			(int)(u8)((a>>8 )&0xff),
29972b15cb3dSCy Schubert 			(int)(u8)((a>>16)&0xff),
29982b15cb3dSCy Schubert 			(int)(u8)((a>>24)&0xff));
29992b15cb3dSCy Schubert 	handle = mm_calloc(1, sizeof(*handle));
30002b15cb3dSCy Schubert 	if (handle == NULL)
30012b15cb3dSCy Schubert 		return NULL;
30022b15cb3dSCy Schubert 	log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
30032b15cb3dSCy Schubert 	EVDNS_LOCK(base);
30042b15cb3dSCy Schubert 	req = request_new(base, handle, TYPE_PTR, buf, flags, callback, ptr);
30052b15cb3dSCy Schubert 	if (req)
30062b15cb3dSCy Schubert 		request_submit(req);
30072b15cb3dSCy Schubert 	if (handle->current_req == NULL) {
30082b15cb3dSCy Schubert 		mm_free(handle);
30092b15cb3dSCy Schubert 		handle = NULL;
30102b15cb3dSCy Schubert 	}
30112b15cb3dSCy Schubert 	EVDNS_UNLOCK(base);
30122b15cb3dSCy Schubert 	return (handle);
30132b15cb3dSCy Schubert }
30142b15cb3dSCy Schubert 
evdns_resolve_reverse(const struct in_addr * in,int flags,evdns_callback_type callback,void * ptr)30152b15cb3dSCy Schubert int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) {
30162b15cb3dSCy Schubert 	return evdns_base_resolve_reverse(current_base, in, flags, callback, ptr)
30172b15cb3dSCy Schubert 		? 0 : -1;
30182b15cb3dSCy Schubert }
30192b15cb3dSCy Schubert 
30202b15cb3dSCy Schubert struct evdns_request *
evdns_base_resolve_reverse_ipv6(struct evdns_base * base,const struct in6_addr * in,int flags,evdns_callback_type callback,void * ptr)30212b15cb3dSCy Schubert evdns_base_resolve_reverse_ipv6(struct evdns_base *base, const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) {
30222b15cb3dSCy Schubert 	/* 32 nybbles, 32 periods, "ip6.arpa", NUL. */
30232b15cb3dSCy Schubert 	char buf[73];
30242b15cb3dSCy Schubert 	char *cp;
30252b15cb3dSCy Schubert 	struct evdns_request *handle;
30262b15cb3dSCy Schubert 	struct request *req;
30272b15cb3dSCy Schubert 	int i;
30282b15cb3dSCy Schubert 	EVUTIL_ASSERT(in);
30292b15cb3dSCy Schubert 	cp = buf;
30302b15cb3dSCy Schubert 	for (i=15; i >= 0; --i) {
30312b15cb3dSCy Schubert 		u8 byte = in->s6_addr[i];
30322b15cb3dSCy Schubert 		*cp++ = "0123456789abcdef"[byte & 0x0f];
30332b15cb3dSCy Schubert 		*cp++ = '.';
30342b15cb3dSCy Schubert 		*cp++ = "0123456789abcdef"[byte >> 4];
30352b15cb3dSCy Schubert 		*cp++ = '.';
30362b15cb3dSCy Schubert 	}
30372b15cb3dSCy Schubert 	EVUTIL_ASSERT(cp + strlen("ip6.arpa") < buf+sizeof(buf));
30382b15cb3dSCy Schubert 	memcpy(cp, "ip6.arpa", strlen("ip6.arpa")+1);
30392b15cb3dSCy Schubert 	handle = mm_calloc(1, sizeof(*handle));
30402b15cb3dSCy Schubert 	if (handle == NULL)
30412b15cb3dSCy Schubert 		return NULL;
30422b15cb3dSCy Schubert 	log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
30432b15cb3dSCy Schubert 	EVDNS_LOCK(base);
30442b15cb3dSCy Schubert 	req = request_new(base, handle, TYPE_PTR, buf, flags, callback, ptr);
30452b15cb3dSCy Schubert 	if (req)
30462b15cb3dSCy Schubert 		request_submit(req);
30472b15cb3dSCy Schubert 	if (handle->current_req == NULL) {
30482b15cb3dSCy Schubert 		mm_free(handle);
30492b15cb3dSCy Schubert 		handle = NULL;
30502b15cb3dSCy Schubert 	}
30512b15cb3dSCy Schubert 	EVDNS_UNLOCK(base);
30522b15cb3dSCy Schubert 	return (handle);
30532b15cb3dSCy Schubert }
30542b15cb3dSCy Schubert 
evdns_resolve_reverse_ipv6(const struct in6_addr * in,int flags,evdns_callback_type callback,void * ptr)30552b15cb3dSCy Schubert int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) {
30562b15cb3dSCy Schubert 	return evdns_base_resolve_reverse_ipv6(current_base, in, flags, callback, ptr)
30572b15cb3dSCy Schubert 		? 0 : -1;
30582b15cb3dSCy Schubert }
30592b15cb3dSCy Schubert 
30602b15cb3dSCy Schubert /* ================================================================= */
30612b15cb3dSCy Schubert /* Search support */
30622b15cb3dSCy Schubert /* */
30632b15cb3dSCy Schubert /* the libc resolver has support for searching a number of domains */
30642b15cb3dSCy Schubert /* to find a name. If nothing else then it takes the single domain */
30652b15cb3dSCy Schubert /* from the gethostname() call. */
30662b15cb3dSCy Schubert /* */
30672b15cb3dSCy Schubert /* It can also be configured via the domain and search options in a */
30682b15cb3dSCy Schubert /* resolv.conf. */
30692b15cb3dSCy Schubert /* */
30702b15cb3dSCy Schubert /* The ndots option controls how many dots it takes for the resolver */
30712b15cb3dSCy Schubert /* to decide that a name is non-local and so try a raw lookup first. */
30722b15cb3dSCy Schubert 
30732b15cb3dSCy Schubert struct search_domain {
30742b15cb3dSCy Schubert 	int len;
30752b15cb3dSCy Schubert 	struct search_domain *next;
30762b15cb3dSCy Schubert 	/* the text string is appended to this structure */
30772b15cb3dSCy Schubert };
30782b15cb3dSCy Schubert 
30792b15cb3dSCy Schubert struct search_state {
30802b15cb3dSCy Schubert 	int refcount;
30812b15cb3dSCy Schubert 	int ndots;
30822b15cb3dSCy Schubert 	int num_domains;
30832b15cb3dSCy Schubert 	struct search_domain *head;
30842b15cb3dSCy Schubert };
30852b15cb3dSCy Schubert 
30862b15cb3dSCy Schubert static void
search_state_decref(struct search_state * const state)30872b15cb3dSCy Schubert search_state_decref(struct search_state *const state) {
30882b15cb3dSCy Schubert 	if (!state) return;
30892b15cb3dSCy Schubert 	state->refcount--;
30902b15cb3dSCy Schubert 	if (!state->refcount) {
30912b15cb3dSCy Schubert 		struct search_domain *next, *dom;
30922b15cb3dSCy Schubert 		for (dom = state->head; dom; dom = next) {
30932b15cb3dSCy Schubert 			next = dom->next;
30942b15cb3dSCy Schubert 			mm_free(dom);
30952b15cb3dSCy Schubert 		}
30962b15cb3dSCy Schubert 		mm_free(state);
30972b15cb3dSCy Schubert 	}
30982b15cb3dSCy Schubert }
30992b15cb3dSCy Schubert 
31002b15cb3dSCy Schubert static struct search_state *
search_state_new(void)31012b15cb3dSCy Schubert search_state_new(void) {
31022b15cb3dSCy Schubert 	struct search_state *state = (struct search_state *) mm_malloc(sizeof(struct search_state));
31032b15cb3dSCy Schubert 	if (!state) return NULL;
31042b15cb3dSCy Schubert 	memset(state, 0, sizeof(struct search_state));
31052b15cb3dSCy Schubert 	state->refcount = 1;
31062b15cb3dSCy Schubert 	state->ndots = 1;
31072b15cb3dSCy Schubert 
31082b15cb3dSCy Schubert 	return state;
31092b15cb3dSCy Schubert }
31102b15cb3dSCy Schubert 
31112b15cb3dSCy Schubert static void
search_postfix_clear(struct evdns_base * base)31122b15cb3dSCy Schubert search_postfix_clear(struct evdns_base *base) {
31132b15cb3dSCy Schubert 	search_state_decref(base->global_search_state);
31142b15cb3dSCy Schubert 
31152b15cb3dSCy Schubert 	base->global_search_state = search_state_new();
31162b15cb3dSCy Schubert }
31172b15cb3dSCy Schubert 
31182b15cb3dSCy Schubert /* exported function */
31192b15cb3dSCy Schubert void
evdns_base_search_clear(struct evdns_base * base)31202b15cb3dSCy Schubert evdns_base_search_clear(struct evdns_base *base)
31212b15cb3dSCy Schubert {
31222b15cb3dSCy Schubert 	EVDNS_LOCK(base);
31232b15cb3dSCy Schubert 	search_postfix_clear(base);
31242b15cb3dSCy Schubert 	EVDNS_UNLOCK(base);
31252b15cb3dSCy Schubert }
31262b15cb3dSCy Schubert 
31272b15cb3dSCy Schubert void
evdns_search_clear(void)31282b15cb3dSCy Schubert evdns_search_clear(void) {
31292b15cb3dSCy Schubert 	evdns_base_search_clear(current_base);
31302b15cb3dSCy Schubert }
31312b15cb3dSCy Schubert 
31322b15cb3dSCy Schubert static void
search_postfix_add(struct evdns_base * base,const char * domain)31332b15cb3dSCy Schubert search_postfix_add(struct evdns_base *base, const char *domain) {
31342b15cb3dSCy Schubert 	size_t domain_len;
31352b15cb3dSCy Schubert 	struct search_domain *sdomain;
31362b15cb3dSCy Schubert 	while (domain[0] == '.') domain++;
31372b15cb3dSCy Schubert 	domain_len = strlen(domain);
31382b15cb3dSCy Schubert 
31392b15cb3dSCy Schubert 	ASSERT_LOCKED(base);
31402b15cb3dSCy Schubert 	if (!base->global_search_state) base->global_search_state = search_state_new();
31412b15cb3dSCy Schubert 	if (!base->global_search_state) return;
31422b15cb3dSCy Schubert 	base->global_search_state->num_domains++;
31432b15cb3dSCy Schubert 
31442b15cb3dSCy Schubert 	sdomain = (struct search_domain *) mm_malloc(sizeof(struct search_domain) + domain_len);
31452b15cb3dSCy Schubert 	if (!sdomain) return;
31462b15cb3dSCy Schubert 	memcpy( ((u8 *) sdomain) + sizeof(struct search_domain), domain, domain_len);
31472b15cb3dSCy Schubert 	sdomain->next = base->global_search_state->head;
31482b15cb3dSCy Schubert 	sdomain->len = (int) domain_len;
31492b15cb3dSCy Schubert 
31502b15cb3dSCy Schubert 	base->global_search_state->head = sdomain;
31512b15cb3dSCy Schubert }
31522b15cb3dSCy Schubert 
31532b15cb3dSCy Schubert /* reverse the order of members in the postfix list. This is needed because, */
31542b15cb3dSCy Schubert /* when parsing resolv.conf we push elements in the wrong order */
31552b15cb3dSCy Schubert static void
search_reverse(struct evdns_base * base)31562b15cb3dSCy Schubert search_reverse(struct evdns_base *base) {
31572b15cb3dSCy Schubert 	struct search_domain *cur, *prev = NULL, *next;
31582b15cb3dSCy Schubert 	ASSERT_LOCKED(base);
31592b15cb3dSCy Schubert 	cur = base->global_search_state->head;
31602b15cb3dSCy Schubert 	while (cur) {
31612b15cb3dSCy Schubert 		next = cur->next;
31622b15cb3dSCy Schubert 		cur->next = prev;
31632b15cb3dSCy Schubert 		prev = cur;
31642b15cb3dSCy Schubert 		cur = next;
31652b15cb3dSCy Schubert 	}
31662b15cb3dSCy Schubert 
31672b15cb3dSCy Schubert 	base->global_search_state->head = prev;
31682b15cb3dSCy Schubert }
31692b15cb3dSCy Schubert 
31702b15cb3dSCy Schubert /* exported function */
31712b15cb3dSCy Schubert void
evdns_base_search_add(struct evdns_base * base,const char * domain)31722b15cb3dSCy Schubert evdns_base_search_add(struct evdns_base *base, const char *domain) {
31732b15cb3dSCy Schubert 	EVDNS_LOCK(base);
31742b15cb3dSCy Schubert 	search_postfix_add(base, domain);
31752b15cb3dSCy Schubert 	EVDNS_UNLOCK(base);
31762b15cb3dSCy Schubert }
31772b15cb3dSCy Schubert void
evdns_search_add(const char * domain)31782b15cb3dSCy Schubert evdns_search_add(const char *domain) {
31792b15cb3dSCy Schubert 	evdns_base_search_add(current_base, domain);
31802b15cb3dSCy Schubert }
31812b15cb3dSCy Schubert 
31822b15cb3dSCy Schubert /* exported function */
31832b15cb3dSCy Schubert void
evdns_base_search_ndots_set(struct evdns_base * base,const int ndots)31842b15cb3dSCy Schubert evdns_base_search_ndots_set(struct evdns_base *base, const int ndots) {
31852b15cb3dSCy Schubert 	EVDNS_LOCK(base);
31862b15cb3dSCy Schubert 	if (!base->global_search_state) base->global_search_state = search_state_new();
31872b15cb3dSCy Schubert 	if (base->global_search_state)
31882b15cb3dSCy Schubert 		base->global_search_state->ndots = ndots;
31892b15cb3dSCy Schubert 	EVDNS_UNLOCK(base);
31902b15cb3dSCy Schubert }
31912b15cb3dSCy Schubert void
evdns_search_ndots_set(const int ndots)31922b15cb3dSCy Schubert evdns_search_ndots_set(const int ndots) {
31932b15cb3dSCy Schubert 	evdns_base_search_ndots_set(current_base, ndots);
31942b15cb3dSCy Schubert }
31952b15cb3dSCy Schubert 
31962b15cb3dSCy Schubert static void
search_set_from_hostname(struct evdns_base * base)31972b15cb3dSCy Schubert search_set_from_hostname(struct evdns_base *base) {
31982b15cb3dSCy Schubert 	char hostname[HOST_NAME_MAX + 1], *domainname;
31992b15cb3dSCy Schubert 
32002b15cb3dSCy Schubert 	ASSERT_LOCKED(base);
32012b15cb3dSCy Schubert 	search_postfix_clear(base);
32022b15cb3dSCy Schubert 	if (gethostname(hostname, sizeof(hostname))) return;
32032b15cb3dSCy Schubert 	domainname = strchr(hostname, '.');
32042b15cb3dSCy Schubert 	if (!domainname) return;
32052b15cb3dSCy Schubert 	search_postfix_add(base, domainname);
32062b15cb3dSCy Schubert }
32072b15cb3dSCy Schubert 
32082b15cb3dSCy Schubert /* warning: returns malloced string */
32092b15cb3dSCy Schubert static char *
search_make_new(const struct search_state * const state,int n,const char * const base_name)32102b15cb3dSCy Schubert search_make_new(const struct search_state *const state, int n, const char *const base_name) {
32112b15cb3dSCy Schubert 	const size_t base_len = strlen(base_name);
3212*a466cc55SCy Schubert 	char need_to_append_dot;
32132b15cb3dSCy Schubert 	struct search_domain *dom;
32142b15cb3dSCy Schubert 
3215*a466cc55SCy Schubert 	if (!base_len) return NULL;
3216*a466cc55SCy Schubert 	need_to_append_dot = base_name[base_len - 1] == '.' ? 0 : 1;
3217*a466cc55SCy Schubert 
32182b15cb3dSCy Schubert 	for (dom = state->head; dom; dom = dom->next) {
32192b15cb3dSCy Schubert 		if (!n--) {
32202b15cb3dSCy Schubert 			/* this is the postfix we want */
32212b15cb3dSCy Schubert 			/* the actual postfix string is kept at the end of the structure */
32222b15cb3dSCy Schubert 			const u8 *const postfix = ((u8 *) dom) + sizeof(struct search_domain);
32232b15cb3dSCy Schubert 			const int postfix_len = dom->len;
32242b15cb3dSCy Schubert 			char *const newname = (char *) mm_malloc(base_len + need_to_append_dot + postfix_len + 1);
32252b15cb3dSCy Schubert 			if (!newname) return NULL;
32262b15cb3dSCy Schubert 			memcpy(newname, base_name, base_len);
32272b15cb3dSCy Schubert 			if (need_to_append_dot) newname[base_len] = '.';
32282b15cb3dSCy Schubert 			memcpy(newname + base_len + need_to_append_dot, postfix, postfix_len);
32292b15cb3dSCy Schubert 			newname[base_len + need_to_append_dot + postfix_len] = 0;
32302b15cb3dSCy Schubert 			return newname;
32312b15cb3dSCy Schubert 		}
32322b15cb3dSCy Schubert 	}
32332b15cb3dSCy Schubert 
32342b15cb3dSCy Schubert 	/* we ran off the end of the list and still didn't find the requested string */
32352b15cb3dSCy Schubert 	EVUTIL_ASSERT(0);
32362b15cb3dSCy Schubert 	return NULL; /* unreachable; stops warnings in some compilers. */
32372b15cb3dSCy Schubert }
32382b15cb3dSCy Schubert 
32392b15cb3dSCy Schubert static 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)32402b15cb3dSCy Schubert search_request_new(struct evdns_base *base, struct evdns_request *handle,
32412b15cb3dSCy Schubert 		   int type, const char *const name, int flags,
32422b15cb3dSCy Schubert 		   evdns_callback_type user_callback, void *user_arg) {
32432b15cb3dSCy Schubert 	ASSERT_LOCKED(base);
32442b15cb3dSCy Schubert 	EVUTIL_ASSERT(type == TYPE_A || type == TYPE_AAAA);
32452b15cb3dSCy Schubert 	EVUTIL_ASSERT(handle->current_req == NULL);
32462b15cb3dSCy Schubert 	if ( ((flags & DNS_QUERY_NO_SEARCH) == 0) &&
32472b15cb3dSCy Schubert 	     base->global_search_state &&
32482b15cb3dSCy Schubert 		 base->global_search_state->num_domains) {
32492b15cb3dSCy Schubert 		/* we have some domains to search */
32502b15cb3dSCy Schubert 		struct request *req;
32512b15cb3dSCy Schubert 		if (string_num_dots(name) >= base->global_search_state->ndots) {
32522b15cb3dSCy Schubert 			req = request_new(base, handle, type, name, flags, user_callback, user_arg);
32532b15cb3dSCy Schubert 			if (!req) return NULL;
32542b15cb3dSCy Schubert 			handle->search_index = -1;
32552b15cb3dSCy Schubert 		} else {
32562b15cb3dSCy Schubert 			char *const new_name = search_make_new(base->global_search_state, 0, name);
32572b15cb3dSCy Schubert 			if (!new_name) return NULL;
32582b15cb3dSCy Schubert 			req = request_new(base, handle, type, new_name, flags, user_callback, user_arg);
32592b15cb3dSCy Schubert 			mm_free(new_name);
32602b15cb3dSCy Schubert 			if (!req) return NULL;
32612b15cb3dSCy Schubert 			handle->search_index = 0;
32622b15cb3dSCy Schubert 		}
32632b15cb3dSCy Schubert 		EVUTIL_ASSERT(handle->search_origname == NULL);
32642b15cb3dSCy Schubert 		handle->search_origname = mm_strdup(name);
32652b15cb3dSCy Schubert 		if (handle->search_origname == NULL) {
32662b15cb3dSCy Schubert 			/* XXX Should we dealloc req? If yes, how? */
32672b15cb3dSCy Schubert 			if (req)
32682b15cb3dSCy Schubert 				mm_free(req);
32692b15cb3dSCy Schubert 			return NULL;
32702b15cb3dSCy Schubert 		}
32712b15cb3dSCy Schubert 		handle->search_state = base->global_search_state;
32722b15cb3dSCy Schubert 		handle->search_flags = flags;
32732b15cb3dSCy Schubert 		base->global_search_state->refcount++;
32742b15cb3dSCy Schubert 		request_submit(req);
32752b15cb3dSCy Schubert 		return req;
32762b15cb3dSCy Schubert 	} else {
32772b15cb3dSCy Schubert 		struct request *const req = request_new(base, handle, type, name, flags, user_callback, user_arg);
32782b15cb3dSCy Schubert 		if (!req) return NULL;
32792b15cb3dSCy Schubert 		request_submit(req);
32802b15cb3dSCy Schubert 		return req;
32812b15cb3dSCy Schubert 	}
32822b15cb3dSCy Schubert }
32832b15cb3dSCy Schubert 
32842b15cb3dSCy Schubert /* this is called when a request has failed to find a name. We need to check */
32852b15cb3dSCy Schubert /* if it is part of a search and, if so, try the next name in the list */
32862b15cb3dSCy Schubert /* returns: */
32872b15cb3dSCy Schubert /*   0 another request has been submitted */
32882b15cb3dSCy Schubert /*   1 no more requests needed */
32892b15cb3dSCy Schubert static int
search_try_next(struct evdns_request * const handle)32902b15cb3dSCy Schubert search_try_next(struct evdns_request *const handle) {
32912b15cb3dSCy Schubert 	struct request *req = handle->current_req;
32922b15cb3dSCy Schubert 	struct evdns_base *base = req->base;
32932b15cb3dSCy Schubert 	struct request *newreq;
32942b15cb3dSCy Schubert 	ASSERT_LOCKED(base);
32952b15cb3dSCy Schubert 	if (handle->search_state) {
32962b15cb3dSCy Schubert 		/* it is part of a search */
32972b15cb3dSCy Schubert 		char *new_name;
32982b15cb3dSCy Schubert 		handle->search_index++;
32992b15cb3dSCy Schubert 		if (handle->search_index >= handle->search_state->num_domains) {
33002b15cb3dSCy Schubert 			/* no more postfixes to try, however we may need to try */
33012b15cb3dSCy Schubert 			/* this name without a postfix */
33022b15cb3dSCy Schubert 			if (string_num_dots(handle->search_origname) < handle->search_state->ndots) {
33032b15cb3dSCy Schubert 				/* yep, we need to try it raw */
33042b15cb3dSCy Schubert 				newreq = request_new(base, NULL, req->request_type, handle->search_origname, handle->search_flags, req->user_callback, req->user_pointer);
33052b15cb3dSCy Schubert 				log(EVDNS_LOG_DEBUG, "Search: trying raw query %s", handle->search_origname);
33062b15cb3dSCy Schubert 				if (newreq) {
33072b15cb3dSCy Schubert 					search_request_finished(handle);
33082b15cb3dSCy Schubert 					goto submit_next;
33092b15cb3dSCy Schubert 				}
33102b15cb3dSCy Schubert 			}
33112b15cb3dSCy Schubert 			return 1;
33122b15cb3dSCy Schubert 		}
33132b15cb3dSCy Schubert 
33142b15cb3dSCy Schubert 		new_name = search_make_new(handle->search_state, handle->search_index, handle->search_origname);
33152b15cb3dSCy Schubert 		if (!new_name) return 1;
33162b15cb3dSCy Schubert 		log(EVDNS_LOG_DEBUG, "Search: now trying %s (%d)", new_name, handle->search_index);
33172b15cb3dSCy Schubert 		newreq = request_new(base, NULL, req->request_type, new_name, handle->search_flags, req->user_callback, req->user_pointer);
33182b15cb3dSCy Schubert 		mm_free(new_name);
33192b15cb3dSCy Schubert 		if (!newreq) return 1;
33202b15cb3dSCy Schubert 		goto submit_next;
33212b15cb3dSCy Schubert 	}
33222b15cb3dSCy Schubert 	return 1;
33232b15cb3dSCy Schubert 
33242b15cb3dSCy Schubert submit_next:
33252b15cb3dSCy Schubert 	request_finished(req, &REQ_HEAD(req->base, req->trans_id), 0);
33262b15cb3dSCy Schubert 	handle->current_req = newreq;
33272b15cb3dSCy Schubert 	newreq->handle = handle;
33282b15cb3dSCy Schubert 	request_submit(newreq);
33292b15cb3dSCy Schubert 	return 0;
33302b15cb3dSCy Schubert }
33312b15cb3dSCy Schubert 
33322b15cb3dSCy Schubert static void
search_request_finished(struct evdns_request * const handle)33332b15cb3dSCy Schubert search_request_finished(struct evdns_request *const handle) {
33342b15cb3dSCy Schubert 	ASSERT_LOCKED(handle->current_req->base);
33352b15cb3dSCy Schubert 	if (handle->search_state) {
33362b15cb3dSCy Schubert 		search_state_decref(handle->search_state);
33372b15cb3dSCy Schubert 		handle->search_state = NULL;
33382b15cb3dSCy Schubert 	}
33392b15cb3dSCy Schubert 	if (handle->search_origname) {
33402b15cb3dSCy Schubert 		mm_free(handle->search_origname);
33412b15cb3dSCy Schubert 		handle->search_origname = NULL;
33422b15cb3dSCy Schubert 	}
33432b15cb3dSCy Schubert }
33442b15cb3dSCy Schubert 
33452b15cb3dSCy Schubert /* ================================================================= */
33462b15cb3dSCy Schubert /* Parsing resolv.conf files */
33472b15cb3dSCy Schubert 
33482b15cb3dSCy Schubert static void
evdns_resolv_set_defaults(struct evdns_base * base,int flags)33492b15cb3dSCy Schubert evdns_resolv_set_defaults(struct evdns_base *base, int flags) {
3350*a466cc55SCy Schubert 	int add_default = flags & DNS_OPTION_NAMESERVERS;
3351*a466cc55SCy Schubert 	if (flags & DNS_OPTION_NAMESERVERS_NO_DEFAULT)
3352*a466cc55SCy Schubert 		add_default = 0;
3353*a466cc55SCy Schubert 
33542b15cb3dSCy Schubert 	/* if the file isn't found then we assume a local resolver */
33552b15cb3dSCy Schubert 	ASSERT_LOCKED(base);
3356*a466cc55SCy Schubert 	if (flags & DNS_OPTION_SEARCH)
3357*a466cc55SCy Schubert 		search_set_from_hostname(base);
3358*a466cc55SCy Schubert 	if (add_default)
3359*a466cc55SCy Schubert 		evdns_base_nameserver_ip_add(base, "127.0.0.1");
33602b15cb3dSCy Schubert }
33612b15cb3dSCy Schubert 
33622b15cb3dSCy Schubert #ifndef EVENT__HAVE_STRTOK_R
33632b15cb3dSCy Schubert static char *
strtok_r(char * s,const char * delim,char ** state)33642b15cb3dSCy Schubert strtok_r(char *s, const char *delim, char **state) {
33652b15cb3dSCy Schubert 	char *cp, *start;
33662b15cb3dSCy Schubert 	start = cp = s ? s : *state;
33672b15cb3dSCy Schubert 	if (!cp)
33682b15cb3dSCy Schubert 		return NULL;
33692b15cb3dSCy Schubert 	while (*cp && !strchr(delim, *cp))
33702b15cb3dSCy Schubert 		++cp;
33712b15cb3dSCy Schubert 	if (!*cp) {
33722b15cb3dSCy Schubert 		if (cp == start)
33732b15cb3dSCy Schubert 			return NULL;
33742b15cb3dSCy Schubert 		*state = NULL;
33752b15cb3dSCy Schubert 		return start;
33762b15cb3dSCy Schubert 	} else {
33772b15cb3dSCy Schubert 		*cp++ = '\0';
33782b15cb3dSCy Schubert 		*state = cp;
33792b15cb3dSCy Schubert 		return start;
33802b15cb3dSCy Schubert 	}
33812b15cb3dSCy Schubert }
33822b15cb3dSCy Schubert #endif
33832b15cb3dSCy Schubert 
33842b15cb3dSCy Schubert /* helper version of atoi which returns -1 on error */
33852b15cb3dSCy Schubert static int
strtoint(const char * const str)33862b15cb3dSCy Schubert strtoint(const char *const str)
33872b15cb3dSCy Schubert {
33882b15cb3dSCy Schubert 	char *endptr;
33892b15cb3dSCy Schubert 	const int r = strtol(str, &endptr, 10);
33902b15cb3dSCy Schubert 	if (*endptr) return -1;
33912b15cb3dSCy Schubert 	return r;
33922b15cb3dSCy Schubert }
33932b15cb3dSCy Schubert 
33942b15cb3dSCy Schubert /* Parse a number of seconds into a timeval; return -1 on error. */
33952b15cb3dSCy Schubert static int
evdns_strtotimeval(const char * const str,struct timeval * out)3396a25439b6SCy Schubert evdns_strtotimeval(const char *const str, struct timeval *out)
33972b15cb3dSCy Schubert {
33982b15cb3dSCy Schubert 	double d;
33992b15cb3dSCy Schubert 	char *endptr;
34002b15cb3dSCy Schubert 	d = strtod(str, &endptr);
34012b15cb3dSCy Schubert 	if (*endptr) return -1;
34022b15cb3dSCy Schubert 	if (d < 0) return -1;
34032b15cb3dSCy Schubert 	out->tv_sec = (int) d;
34042b15cb3dSCy Schubert 	out->tv_usec = (int) ((d - (int) d)*1000000);
34052b15cb3dSCy Schubert 	if (out->tv_sec == 0 && out->tv_usec < 1000) /* less than 1 msec */
34062b15cb3dSCy Schubert 		return -1;
34072b15cb3dSCy Schubert 	return 0;
34082b15cb3dSCy Schubert }
34092b15cb3dSCy Schubert 
34102b15cb3dSCy Schubert /* helper version of atoi that returns -1 on error and clips to bounds. */
34112b15cb3dSCy Schubert static int
strtoint_clipped(const char * const str,int min,int max)34122b15cb3dSCy Schubert strtoint_clipped(const char *const str, int min, int max)
34132b15cb3dSCy Schubert {
34142b15cb3dSCy Schubert 	int r = strtoint(str);
34152b15cb3dSCy Schubert 	if (r == -1)
34162b15cb3dSCy Schubert 		return r;
34172b15cb3dSCy Schubert 	else if (r<min)
34182b15cb3dSCy Schubert 		return min;
34192b15cb3dSCy Schubert 	else if (r>max)
34202b15cb3dSCy Schubert 		return max;
34212b15cb3dSCy Schubert 	else
34222b15cb3dSCy Schubert 		return r;
34232b15cb3dSCy Schubert }
34242b15cb3dSCy Schubert 
34252b15cb3dSCy Schubert static int
evdns_base_set_max_requests_inflight(struct evdns_base * base,int maxinflight)34262b15cb3dSCy Schubert evdns_base_set_max_requests_inflight(struct evdns_base *base, int maxinflight)
34272b15cb3dSCy Schubert {
34282b15cb3dSCy Schubert 	int old_n_heads = base->n_req_heads, n_heads;
34292b15cb3dSCy Schubert 	struct request **old_heads = base->req_heads, **new_heads, *req;
34302b15cb3dSCy Schubert 	int i;
34312b15cb3dSCy Schubert 
34322b15cb3dSCy Schubert 	ASSERT_LOCKED(base);
34332b15cb3dSCy Schubert 	if (maxinflight < 1)
34342b15cb3dSCy Schubert 		maxinflight = 1;
34352b15cb3dSCy Schubert 	n_heads = (maxinflight+4) / 5;
34362b15cb3dSCy Schubert 	EVUTIL_ASSERT(n_heads > 0);
34372b15cb3dSCy Schubert 	new_heads = mm_calloc(n_heads, sizeof(struct request*));
34382b15cb3dSCy Schubert 	if (!new_heads)
34392b15cb3dSCy Schubert 		return (-1);
34402b15cb3dSCy Schubert 	if (old_heads) {
34412b15cb3dSCy Schubert 		for (i = 0; i < old_n_heads; ++i) {
34422b15cb3dSCy Schubert 			while (old_heads[i]) {
34432b15cb3dSCy Schubert 				req = old_heads[i];
34442b15cb3dSCy Schubert 				evdns_request_remove(req, &old_heads[i]);
34452b15cb3dSCy Schubert 				evdns_request_insert(req, &new_heads[req->trans_id % n_heads]);
34462b15cb3dSCy Schubert 			}
34472b15cb3dSCy Schubert 		}
34482b15cb3dSCy Schubert 		mm_free(old_heads);
34492b15cb3dSCy Schubert 	}
34502b15cb3dSCy Schubert 	base->req_heads = new_heads;
34512b15cb3dSCy Schubert 	base->n_req_heads = n_heads;
34522b15cb3dSCy Schubert 	base->global_max_requests_inflight = maxinflight;
34532b15cb3dSCy Schubert 	return (0);
34542b15cb3dSCy Schubert }
34552b15cb3dSCy Schubert 
34562b15cb3dSCy Schubert /* exported function */
34572b15cb3dSCy Schubert int
evdns_base_set_option(struct evdns_base * base,const char * option,const char * val)34582b15cb3dSCy Schubert evdns_base_set_option(struct evdns_base *base,
34592b15cb3dSCy Schubert     const char *option, const char *val)
34602b15cb3dSCy Schubert {
34612b15cb3dSCy Schubert 	int res;
34622b15cb3dSCy Schubert 	EVDNS_LOCK(base);
34632b15cb3dSCy Schubert 	res = evdns_base_set_option_impl(base, option, val, DNS_OPTIONS_ALL);
34642b15cb3dSCy Schubert 	EVDNS_UNLOCK(base);
34652b15cb3dSCy Schubert 	return res;
34662b15cb3dSCy Schubert }
34672b15cb3dSCy Schubert 
34682b15cb3dSCy Schubert static inline int
str_matches_option(const char * s1,const char * optionname)34692b15cb3dSCy Schubert str_matches_option(const char *s1, const char *optionname)
34702b15cb3dSCy Schubert {
34712b15cb3dSCy Schubert 	/* Option names are given as "option:" We accept either 'option' in
34722b15cb3dSCy Schubert 	 * s1, or 'option:randomjunk'.  The latter form is to implement the
34732b15cb3dSCy Schubert 	 * resolv.conf parser. */
34742b15cb3dSCy Schubert 	size_t optlen = strlen(optionname);
34752b15cb3dSCy Schubert 	size_t slen = strlen(s1);
34762b15cb3dSCy Schubert 	if (slen == optlen || slen == optlen - 1)
34772b15cb3dSCy Schubert 		return !strncmp(s1, optionname, slen);
34782b15cb3dSCy Schubert 	else if (slen > optlen)
34792b15cb3dSCy Schubert 		return !strncmp(s1, optionname, optlen);
34802b15cb3dSCy Schubert 	else
34812b15cb3dSCy Schubert 		return 0;
34822b15cb3dSCy Schubert }
34832b15cb3dSCy Schubert 
34842b15cb3dSCy Schubert static int
evdns_base_set_option_impl(struct evdns_base * base,const char * option,const char * val,int flags)34852b15cb3dSCy Schubert evdns_base_set_option_impl(struct evdns_base *base,
34862b15cb3dSCy Schubert     const char *option, const char *val, int flags)
34872b15cb3dSCy Schubert {
34882b15cb3dSCy Schubert 	ASSERT_LOCKED(base);
34892b15cb3dSCy Schubert 	if (str_matches_option(option, "ndots:")) {
34902b15cb3dSCy Schubert 		const int ndots = strtoint(val);
34912b15cb3dSCy Schubert 		if (ndots == -1) return -1;
34922b15cb3dSCy Schubert 		if (!(flags & DNS_OPTION_SEARCH)) return 0;
34932b15cb3dSCy Schubert 		log(EVDNS_LOG_DEBUG, "Setting ndots to %d", ndots);
34942b15cb3dSCy Schubert 		if (!base->global_search_state) base->global_search_state = search_state_new();
34952b15cb3dSCy Schubert 		if (!base->global_search_state) return -1;
34962b15cb3dSCy Schubert 		base->global_search_state->ndots = ndots;
34972b15cb3dSCy Schubert 	} else if (str_matches_option(option, "timeout:")) {
34982b15cb3dSCy Schubert 		struct timeval tv;
3499a25439b6SCy Schubert 		if (evdns_strtotimeval(val, &tv) == -1) return -1;
35002b15cb3dSCy Schubert 		if (!(flags & DNS_OPTION_MISC)) return 0;
35012b15cb3dSCy Schubert 		log(EVDNS_LOG_DEBUG, "Setting timeout to %s", val);
35022b15cb3dSCy Schubert 		memcpy(&base->global_timeout, &tv, sizeof(struct timeval));
35032b15cb3dSCy Schubert 	} else if (str_matches_option(option, "getaddrinfo-allow-skew:")) {
35042b15cb3dSCy Schubert 		struct timeval tv;
3505a25439b6SCy Schubert 		if (evdns_strtotimeval(val, &tv) == -1) return -1;
35062b15cb3dSCy Schubert 		if (!(flags & DNS_OPTION_MISC)) return 0;
35072b15cb3dSCy Schubert 		log(EVDNS_LOG_DEBUG, "Setting getaddrinfo-allow-skew to %s",
35082b15cb3dSCy Schubert 		    val);
35092b15cb3dSCy Schubert 		memcpy(&base->global_getaddrinfo_allow_skew, &tv,
35102b15cb3dSCy Schubert 		    sizeof(struct timeval));
35112b15cb3dSCy Schubert 	} else if (str_matches_option(option, "max-timeouts:")) {
35122b15cb3dSCy Schubert 		const int maxtimeout = strtoint_clipped(val, 1, 255);
35132b15cb3dSCy Schubert 		if (maxtimeout == -1) return -1;
35142b15cb3dSCy Schubert 		if (!(flags & DNS_OPTION_MISC)) return 0;
35152b15cb3dSCy Schubert 		log(EVDNS_LOG_DEBUG, "Setting maximum allowed timeouts to %d",
35162b15cb3dSCy Schubert 			maxtimeout);
35172b15cb3dSCy Schubert 		base->global_max_nameserver_timeout = maxtimeout;
35182b15cb3dSCy Schubert 	} else if (str_matches_option(option, "max-inflight:")) {
35192b15cb3dSCy Schubert 		const int maxinflight = strtoint_clipped(val, 1, 65000);
35202b15cb3dSCy Schubert 		if (maxinflight == -1) return -1;
35212b15cb3dSCy Schubert 		if (!(flags & DNS_OPTION_MISC)) return 0;
35222b15cb3dSCy Schubert 		log(EVDNS_LOG_DEBUG, "Setting maximum inflight requests to %d",
35232b15cb3dSCy Schubert 			maxinflight);
35242b15cb3dSCy Schubert 		evdns_base_set_max_requests_inflight(base, maxinflight);
35252b15cb3dSCy Schubert 	} else if (str_matches_option(option, "attempts:")) {
35262b15cb3dSCy Schubert 		int retries = strtoint(val);
35272b15cb3dSCy Schubert 		if (retries == -1) return -1;
35282b15cb3dSCy Schubert 		if (retries > 255) retries = 255;
35292b15cb3dSCy Schubert 		if (!(flags & DNS_OPTION_MISC)) return 0;
35302b15cb3dSCy Schubert 		log(EVDNS_LOG_DEBUG, "Setting retries to %d", retries);
35312b15cb3dSCy Schubert 		base->global_max_retransmits = retries;
35322b15cb3dSCy Schubert 	} else if (str_matches_option(option, "randomize-case:")) {
35332b15cb3dSCy Schubert 		int randcase = strtoint(val);
3534*a466cc55SCy Schubert 		if (randcase == -1) return -1;
35352b15cb3dSCy Schubert 		if (!(flags & DNS_OPTION_MISC)) return 0;
35362b15cb3dSCy Schubert 		base->global_randomize_case = randcase;
35372b15cb3dSCy Schubert 	} else if (str_matches_option(option, "bind-to:")) {
35382b15cb3dSCy Schubert 		/* XXX This only applies to successive nameservers, not
35392b15cb3dSCy Schubert 		 * to already-configured ones.	We might want to fix that. */
35402b15cb3dSCy Schubert 		int len = sizeof(base->global_outgoing_address);
35412b15cb3dSCy Schubert 		if (!(flags & DNS_OPTION_NAMESERVERS)) return 0;
35422b15cb3dSCy Schubert 		if (evutil_parse_sockaddr_port(val,
35432b15cb3dSCy Schubert 			(struct sockaddr*)&base->global_outgoing_address, &len))
35442b15cb3dSCy Schubert 			return -1;
35452b15cb3dSCy Schubert 		base->global_outgoing_addrlen = len;
35462b15cb3dSCy Schubert 	} else if (str_matches_option(option, "initial-probe-timeout:")) {
35472b15cb3dSCy Schubert 		struct timeval tv;
3548a25439b6SCy Schubert 		if (evdns_strtotimeval(val, &tv) == -1) return -1;
35492b15cb3dSCy Schubert 		if (tv.tv_sec > 3600)
35502b15cb3dSCy Schubert 			tv.tv_sec = 3600;
35512b15cb3dSCy Schubert 		if (!(flags & DNS_OPTION_MISC)) return 0;
35522b15cb3dSCy Schubert 		log(EVDNS_LOG_DEBUG, "Setting initial probe timeout to %s",
35532b15cb3dSCy Schubert 		    val);
35542b15cb3dSCy Schubert 		memcpy(&base->global_nameserver_probe_initial_timeout, &tv,
35552b15cb3dSCy Schubert 		    sizeof(tv));
3556*a466cc55SCy Schubert 	} else if (str_matches_option(option, "so-rcvbuf:")) {
3557*a466cc55SCy Schubert 		int buf = strtoint(val);
3558*a466cc55SCy Schubert 		if (buf == -1) return -1;
3559*a466cc55SCy Schubert 		if (!(flags & DNS_OPTION_MISC)) return 0;
3560*a466cc55SCy Schubert 		log(EVDNS_LOG_DEBUG, "Setting SO_RCVBUF to %s", val);
3561*a466cc55SCy Schubert 		base->so_rcvbuf = buf;
3562*a466cc55SCy Schubert 	} else if (str_matches_option(option, "so-sndbuf:")) {
3563*a466cc55SCy Schubert 		int buf = strtoint(val);
3564*a466cc55SCy Schubert 		if (buf == -1) return -1;
3565*a466cc55SCy Schubert 		if (!(flags & DNS_OPTION_MISC)) return 0;
3566*a466cc55SCy Schubert 		log(EVDNS_LOG_DEBUG, "Setting SO_SNDBUF to %s", val);
3567*a466cc55SCy Schubert 		base->so_sndbuf = buf;
35682b15cb3dSCy Schubert 	}
35692b15cb3dSCy Schubert 	return 0;
35702b15cb3dSCy Schubert }
35712b15cb3dSCy Schubert 
35722b15cb3dSCy Schubert int
evdns_set_option(const char * option,const char * val,int flags)35732b15cb3dSCy Schubert evdns_set_option(const char *option, const char *val, int flags)
35742b15cb3dSCy Schubert {
35752b15cb3dSCy Schubert 	if (!current_base)
35762b15cb3dSCy Schubert 		current_base = evdns_base_new(NULL, 0);
35772b15cb3dSCy Schubert 	return evdns_base_set_option(current_base, option, val);
35782b15cb3dSCy Schubert }
35792b15cb3dSCy Schubert 
35802b15cb3dSCy Schubert static void
resolv_conf_parse_line(struct evdns_base * base,char * const start,int flags)35812b15cb3dSCy Schubert resolv_conf_parse_line(struct evdns_base *base, char *const start, int flags) {
35822b15cb3dSCy Schubert 	char *strtok_state;
35832b15cb3dSCy Schubert 	static const char *const delims = " \t";
35842b15cb3dSCy Schubert #define NEXT_TOKEN strtok_r(NULL, delims, &strtok_state)
35852b15cb3dSCy Schubert 
35862b15cb3dSCy Schubert 
35872b15cb3dSCy Schubert 	char *const first_token = strtok_r(start, delims, &strtok_state);
35882b15cb3dSCy Schubert 	ASSERT_LOCKED(base);
35892b15cb3dSCy Schubert 	if (!first_token) return;
35902b15cb3dSCy Schubert 
35912b15cb3dSCy Schubert 	if (!strcmp(first_token, "nameserver") && (flags & DNS_OPTION_NAMESERVERS)) {
35922b15cb3dSCy Schubert 		const char *const nameserver = NEXT_TOKEN;
35932b15cb3dSCy Schubert 
35942b15cb3dSCy Schubert 		if (nameserver)
35952b15cb3dSCy Schubert 			evdns_base_nameserver_ip_add(base, nameserver);
35962b15cb3dSCy Schubert 	} else if (!strcmp(first_token, "domain") && (flags & DNS_OPTION_SEARCH)) {
35972b15cb3dSCy Schubert 		const char *const domain = NEXT_TOKEN;
35982b15cb3dSCy Schubert 		if (domain) {
35992b15cb3dSCy Schubert 			search_postfix_clear(base);
36002b15cb3dSCy Schubert 			search_postfix_add(base, domain);
36012b15cb3dSCy Schubert 		}
36022b15cb3dSCy Schubert 	} else if (!strcmp(first_token, "search") && (flags & DNS_OPTION_SEARCH)) {
36032b15cb3dSCy Schubert 		const char *domain;
36042b15cb3dSCy Schubert 		search_postfix_clear(base);
36052b15cb3dSCy Schubert 
36062b15cb3dSCy Schubert 		while ((domain = NEXT_TOKEN)) {
36072b15cb3dSCy Schubert 			search_postfix_add(base, domain);
36082b15cb3dSCy Schubert 		}
36092b15cb3dSCy Schubert 		search_reverse(base);
36102b15cb3dSCy Schubert 	} else if (!strcmp(first_token, "options")) {
36112b15cb3dSCy Schubert 		const char *option;
36122b15cb3dSCy Schubert 		while ((option = NEXT_TOKEN)) {
36132b15cb3dSCy Schubert 			const char *val = strchr(option, ':');
36142b15cb3dSCy Schubert 			evdns_base_set_option_impl(base, option, val ? val+1 : "", flags);
36152b15cb3dSCy Schubert 		}
36162b15cb3dSCy Schubert 	}
36172b15cb3dSCy Schubert #undef NEXT_TOKEN
36182b15cb3dSCy Schubert }
36192b15cb3dSCy Schubert 
36202b15cb3dSCy Schubert /* exported function */
36212b15cb3dSCy Schubert /* returns: */
36222b15cb3dSCy Schubert /*   0 no errors */
36232b15cb3dSCy Schubert /*   1 failed to open file */
36242b15cb3dSCy Schubert /*   2 failed to stat file */
36252b15cb3dSCy Schubert /*   3 file too large */
36262b15cb3dSCy Schubert /*   4 out of memory */
36272b15cb3dSCy Schubert /*   5 short read from file */
36282b15cb3dSCy Schubert int
evdns_base_resolv_conf_parse(struct evdns_base * base,int flags,const char * const filename)36292b15cb3dSCy Schubert evdns_base_resolv_conf_parse(struct evdns_base *base, int flags, const char *const filename) {
36302b15cb3dSCy Schubert 	int res;
36312b15cb3dSCy Schubert 	EVDNS_LOCK(base);
36322b15cb3dSCy Schubert 	res = evdns_base_resolv_conf_parse_impl(base, flags, filename);
36332b15cb3dSCy Schubert 	EVDNS_UNLOCK(base);
36342b15cb3dSCy Schubert 	return res;
36352b15cb3dSCy Schubert }
36362b15cb3dSCy Schubert 
36372b15cb3dSCy Schubert static char *
evdns_get_default_hosts_filename(void)36382b15cb3dSCy Schubert evdns_get_default_hosts_filename(void)
36392b15cb3dSCy Schubert {
36402b15cb3dSCy Schubert #ifdef _WIN32
36412b15cb3dSCy Schubert 	/* Windows is a little coy about where it puts its configuration
36422b15cb3dSCy Schubert 	 * files.  Sure, they're _usually_ in C:\windows\system32, but
36432b15cb3dSCy Schubert 	 * there's no reason in principle they couldn't be in
36442b15cb3dSCy Schubert 	 * W:\hoboken chicken emergency\
36452b15cb3dSCy Schubert 	 */
36462b15cb3dSCy Schubert 	char path[MAX_PATH+1];
36472b15cb3dSCy Schubert 	static const char hostfile[] = "\\drivers\\etc\\hosts";
36482b15cb3dSCy Schubert 	char *path_out;
36492b15cb3dSCy Schubert 	size_t len_out;
36502b15cb3dSCy Schubert 
36512b15cb3dSCy Schubert 	if (! SHGetSpecialFolderPathA(NULL, path, CSIDL_SYSTEM, 0))
36522b15cb3dSCy Schubert 		return NULL;
3653a25439b6SCy Schubert 	len_out = strlen(path)+strlen(hostfile)+1;
3654a25439b6SCy Schubert 	path_out = mm_malloc(len_out);
36552b15cb3dSCy Schubert 	evutil_snprintf(path_out, len_out, "%s%s", path, hostfile);
36562b15cb3dSCy Schubert 	return path_out;
36572b15cb3dSCy Schubert #else
36582b15cb3dSCy Schubert 	return mm_strdup("/etc/hosts");
36592b15cb3dSCy Schubert #endif
36602b15cb3dSCy Schubert }
36612b15cb3dSCy Schubert 
36622b15cb3dSCy Schubert static int
evdns_base_resolv_conf_parse_impl(struct evdns_base * base,int flags,const char * const filename)36632b15cb3dSCy Schubert evdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags, const char *const filename) {
36642b15cb3dSCy Schubert 	size_t n;
36652b15cb3dSCy Schubert 	char *resolv;
36662b15cb3dSCy Schubert 	char *start;
36672b15cb3dSCy Schubert 	int err = 0;
3668*a466cc55SCy Schubert 	int add_default;
36692b15cb3dSCy Schubert 
36702b15cb3dSCy Schubert 	log(EVDNS_LOG_DEBUG, "Parsing resolv.conf file %s", filename);
36712b15cb3dSCy Schubert 
3672*a466cc55SCy Schubert 	add_default = flags & DNS_OPTION_NAMESERVERS;
3673*a466cc55SCy Schubert 	if (flags & DNS_OPTION_NAMESERVERS_NO_DEFAULT)
3674*a466cc55SCy Schubert 		add_default = 0;
3675*a466cc55SCy Schubert 
36762b15cb3dSCy Schubert 	if (flags & DNS_OPTION_HOSTSFILE) {
36772b15cb3dSCy Schubert 		char *fname = evdns_get_default_hosts_filename();
36782b15cb3dSCy Schubert 		evdns_base_load_hosts(base, fname);
36792b15cb3dSCy Schubert 		if (fname)
36802b15cb3dSCy Schubert 			mm_free(fname);
36812b15cb3dSCy Schubert 	}
36822b15cb3dSCy Schubert 
3683*a466cc55SCy Schubert 	if (!filename) {
3684*a466cc55SCy Schubert 		evdns_resolv_set_defaults(base, flags);
3685*a466cc55SCy Schubert 		return 1;
3686*a466cc55SCy Schubert 	}
3687*a466cc55SCy Schubert 
36882b15cb3dSCy Schubert 	if ((err = evutil_read_file_(filename, &resolv, &n, 0)) < 0) {
36892b15cb3dSCy Schubert 		if (err == -1) {
36902b15cb3dSCy Schubert 			/* No file. */
36912b15cb3dSCy Schubert 			evdns_resolv_set_defaults(base, flags);
36922b15cb3dSCy Schubert 			return 1;
36932b15cb3dSCy Schubert 		} else {
36942b15cb3dSCy Schubert 			return 2;
36952b15cb3dSCy Schubert 		}
36962b15cb3dSCy Schubert 	}
36972b15cb3dSCy Schubert 
36982b15cb3dSCy Schubert 	start = resolv;
36992b15cb3dSCy Schubert 	for (;;) {
37002b15cb3dSCy Schubert 		char *const newline = strchr(start, '\n');
37012b15cb3dSCy Schubert 		if (!newline) {
37022b15cb3dSCy Schubert 			resolv_conf_parse_line(base, start, flags);
37032b15cb3dSCy Schubert 			break;
37042b15cb3dSCy Schubert 		} else {
37052b15cb3dSCy Schubert 			*newline = 0;
37062b15cb3dSCy Schubert 			resolv_conf_parse_line(base, start, flags);
37072b15cb3dSCy Schubert 			start = newline + 1;
37082b15cb3dSCy Schubert 		}
37092b15cb3dSCy Schubert 	}
37102b15cb3dSCy Schubert 
3711*a466cc55SCy Schubert 	if (!base->server_head && add_default) {
37122b15cb3dSCy Schubert 		/* no nameservers were configured. */
37132b15cb3dSCy Schubert 		evdns_base_nameserver_ip_add(base, "127.0.0.1");
37142b15cb3dSCy Schubert 		err = 6;
37152b15cb3dSCy Schubert 	}
37162b15cb3dSCy Schubert 	if (flags & DNS_OPTION_SEARCH && (!base->global_search_state || base->global_search_state->num_domains == 0)) {
37172b15cb3dSCy Schubert 		search_set_from_hostname(base);
37182b15cb3dSCy Schubert 	}
37192b15cb3dSCy Schubert 
37202b15cb3dSCy Schubert 	mm_free(resolv);
37212b15cb3dSCy Schubert 	return err;
37222b15cb3dSCy Schubert }
37232b15cb3dSCy Schubert 
37242b15cb3dSCy Schubert int
evdns_resolv_conf_parse(int flags,const char * const filename)37252b15cb3dSCy Schubert evdns_resolv_conf_parse(int flags, const char *const filename) {
37262b15cb3dSCy Schubert 	if (!current_base)
37272b15cb3dSCy Schubert 		current_base = evdns_base_new(NULL, 0);
37282b15cb3dSCy Schubert 	return evdns_base_resolv_conf_parse(current_base, flags, filename);
37292b15cb3dSCy Schubert }
37302b15cb3dSCy Schubert 
37312b15cb3dSCy Schubert 
37322b15cb3dSCy Schubert #ifdef _WIN32
37332b15cb3dSCy Schubert /* Add multiple nameservers from a space-or-comma-separated list. */
37342b15cb3dSCy Schubert static int
evdns_nameserver_ip_add_line(struct evdns_base * base,const char * ips)37352b15cb3dSCy Schubert evdns_nameserver_ip_add_line(struct evdns_base *base, const char *ips) {
37362b15cb3dSCy Schubert 	const char *addr;
37372b15cb3dSCy Schubert 	char *buf;
37382b15cb3dSCy Schubert 	int r;
37392b15cb3dSCy Schubert 	ASSERT_LOCKED(base);
37402b15cb3dSCy Schubert 	while (*ips) {
37412b15cb3dSCy Schubert 		while (isspace(*ips) || *ips == ',' || *ips == '\t')
37422b15cb3dSCy Schubert 			++ips;
37432b15cb3dSCy Schubert 		addr = ips;
37442b15cb3dSCy Schubert 		while (isdigit(*ips) || *ips == '.' || *ips == ':' ||
37452b15cb3dSCy Schubert 		    *ips=='[' || *ips==']')
37462b15cb3dSCy Schubert 			++ips;
37472b15cb3dSCy Schubert 		buf = mm_malloc(ips-addr+1);
37482b15cb3dSCy Schubert 		if (!buf) return 4;
37492b15cb3dSCy Schubert 		memcpy(buf, addr, ips-addr);
37502b15cb3dSCy Schubert 		buf[ips-addr] = '\0';
37512b15cb3dSCy Schubert 		r = evdns_base_nameserver_ip_add(base, buf);
37522b15cb3dSCy Schubert 		mm_free(buf);
37532b15cb3dSCy Schubert 		if (r) return r;
37542b15cb3dSCy Schubert 	}
37552b15cb3dSCy Schubert 	return 0;
37562b15cb3dSCy Schubert }
37572b15cb3dSCy Schubert 
37582b15cb3dSCy Schubert typedef DWORD(WINAPI *GetNetworkParams_fn_t)(FIXED_INFO *, DWORD*);
37592b15cb3dSCy Schubert 
37602b15cb3dSCy Schubert /* Use the windows GetNetworkParams interface in iphlpapi.dll to */
37612b15cb3dSCy Schubert /* figure out what our nameservers are. */
37622b15cb3dSCy Schubert static int
load_nameservers_with_getnetworkparams(struct evdns_base * base)37632b15cb3dSCy Schubert load_nameservers_with_getnetworkparams(struct evdns_base *base)
37642b15cb3dSCy Schubert {
37652b15cb3dSCy Schubert 	/* Based on MSDN examples and inspection of  c-ares code. */
37662b15cb3dSCy Schubert 	FIXED_INFO *fixed;
37672b15cb3dSCy Schubert 	HMODULE handle = 0;
37682b15cb3dSCy Schubert 	ULONG size = sizeof(FIXED_INFO);
37692b15cb3dSCy Schubert 	void *buf = NULL;
37702b15cb3dSCy Schubert 	int status = 0, r, added_any;
37712b15cb3dSCy Schubert 	IP_ADDR_STRING *ns;
37722b15cb3dSCy Schubert 	GetNetworkParams_fn_t fn;
37732b15cb3dSCy Schubert 
37742b15cb3dSCy Schubert 	ASSERT_LOCKED(base);
37752b15cb3dSCy Schubert 	if (!(handle = evutil_load_windows_system_library_(
37762b15cb3dSCy Schubert 			TEXT("iphlpapi.dll")))) {
37772b15cb3dSCy Schubert 		log(EVDNS_LOG_WARN, "Could not open iphlpapi.dll");
37782b15cb3dSCy Schubert 		status = -1;
37792b15cb3dSCy Schubert 		goto done;
37802b15cb3dSCy Schubert 	}
37812b15cb3dSCy Schubert 	if (!(fn = (GetNetworkParams_fn_t) GetProcAddress(handle, "GetNetworkParams"))) {
37822b15cb3dSCy Schubert 		log(EVDNS_LOG_WARN, "Could not get address of function.");
37832b15cb3dSCy Schubert 		status = -1;
37842b15cb3dSCy Schubert 		goto done;
37852b15cb3dSCy Schubert 	}
37862b15cb3dSCy Schubert 
37872b15cb3dSCy Schubert 	buf = mm_malloc(size);
37882b15cb3dSCy Schubert 	if (!buf) { status = 4; goto done; }
37892b15cb3dSCy Schubert 	fixed = buf;
37902b15cb3dSCy Schubert 	r = fn(fixed, &size);
37912b15cb3dSCy Schubert 	if (r != ERROR_SUCCESS && r != ERROR_BUFFER_OVERFLOW) {
37922b15cb3dSCy Schubert 		status = -1;
37932b15cb3dSCy Schubert 		goto done;
37942b15cb3dSCy Schubert 	}
37952b15cb3dSCy Schubert 	if (r != ERROR_SUCCESS) {
37962b15cb3dSCy Schubert 		mm_free(buf);
37972b15cb3dSCy Schubert 		buf = mm_malloc(size);
37982b15cb3dSCy Schubert 		if (!buf) { status = 4; goto done; }
37992b15cb3dSCy Schubert 		fixed = buf;
38002b15cb3dSCy Schubert 		r = fn(fixed, &size);
38012b15cb3dSCy Schubert 		if (r != ERROR_SUCCESS) {
38022b15cb3dSCy Schubert 			log(EVDNS_LOG_DEBUG, "fn() failed.");
38032b15cb3dSCy Schubert 			status = -1;
38042b15cb3dSCy Schubert 			goto done;
38052b15cb3dSCy Schubert 		}
38062b15cb3dSCy Schubert 	}
38072b15cb3dSCy Schubert 
38082b15cb3dSCy Schubert 	EVUTIL_ASSERT(fixed);
38092b15cb3dSCy Schubert 	added_any = 0;
38102b15cb3dSCy Schubert 	ns = &(fixed->DnsServerList);
38112b15cb3dSCy Schubert 	while (ns) {
38122b15cb3dSCy Schubert 		r = evdns_nameserver_ip_add_line(base, ns->IpAddress.String);
38132b15cb3dSCy Schubert 		if (r) {
38142b15cb3dSCy Schubert 			log(EVDNS_LOG_DEBUG,"Could not add nameserver %s to list,error: %d",
38152b15cb3dSCy Schubert 				(ns->IpAddress.String),(int)GetLastError());
38162b15cb3dSCy Schubert 			status = r;
38172b15cb3dSCy Schubert 		} else {
38182b15cb3dSCy Schubert 			++added_any;
38192b15cb3dSCy Schubert 			log(EVDNS_LOG_DEBUG,"Successfully added %s as nameserver",ns->IpAddress.String);
38202b15cb3dSCy Schubert 		}
38212b15cb3dSCy Schubert 
38222b15cb3dSCy Schubert 		ns = ns->Next;
38232b15cb3dSCy Schubert 	}
38242b15cb3dSCy Schubert 
38252b15cb3dSCy Schubert 	if (!added_any) {
38262b15cb3dSCy Schubert 		log(EVDNS_LOG_DEBUG, "No nameservers added.");
38272b15cb3dSCy Schubert 		if (status == 0)
38282b15cb3dSCy Schubert 			status = -1;
38292b15cb3dSCy Schubert 	} else {
38302b15cb3dSCy Schubert 		status = 0;
38312b15cb3dSCy Schubert 	}
38322b15cb3dSCy Schubert 
38332b15cb3dSCy Schubert  done:
38342b15cb3dSCy Schubert 	if (buf)
38352b15cb3dSCy Schubert 		mm_free(buf);
38362b15cb3dSCy Schubert 	if (handle)
38372b15cb3dSCy Schubert 		FreeLibrary(handle);
38382b15cb3dSCy Schubert 	return status;
38392b15cb3dSCy Schubert }
38402b15cb3dSCy Schubert 
38412b15cb3dSCy Schubert static int
config_nameserver_from_reg_key(struct evdns_base * base,HKEY key,const TCHAR * subkey)38422b15cb3dSCy Schubert config_nameserver_from_reg_key(struct evdns_base *base, HKEY key, const TCHAR *subkey)
38432b15cb3dSCy Schubert {
38442b15cb3dSCy Schubert 	char *buf;
38452b15cb3dSCy Schubert 	DWORD bufsz = 0, type = 0;
38462b15cb3dSCy Schubert 	int status = 0;
38472b15cb3dSCy Schubert 
38482b15cb3dSCy Schubert 	ASSERT_LOCKED(base);
38492b15cb3dSCy Schubert 	if (RegQueryValueEx(key, subkey, 0, &type, NULL, &bufsz)
38502b15cb3dSCy Schubert 	    != ERROR_MORE_DATA)
38512b15cb3dSCy Schubert 		return -1;
38522b15cb3dSCy Schubert 	if (!(buf = mm_malloc(bufsz)))
38532b15cb3dSCy Schubert 		return -1;
38542b15cb3dSCy Schubert 
38552b15cb3dSCy Schubert 	if (RegQueryValueEx(key, subkey, 0, &type, (LPBYTE)buf, &bufsz)
38562b15cb3dSCy Schubert 	    == ERROR_SUCCESS && bufsz > 1) {
38572b15cb3dSCy Schubert 		status = evdns_nameserver_ip_add_line(base,buf);
38582b15cb3dSCy Schubert 	}
38592b15cb3dSCy Schubert 
38602b15cb3dSCy Schubert 	mm_free(buf);
38612b15cb3dSCy Schubert 	return status;
38622b15cb3dSCy Schubert }
38632b15cb3dSCy Schubert 
38642b15cb3dSCy Schubert #define SERVICES_KEY TEXT("System\\CurrentControlSet\\Services\\")
38652b15cb3dSCy Schubert #define WIN_NS_9X_KEY  SERVICES_KEY TEXT("VxD\\MSTCP")
38662b15cb3dSCy Schubert #define WIN_NS_NT_KEY  SERVICES_KEY TEXT("Tcpip\\Parameters")
38672b15cb3dSCy Schubert 
38682b15cb3dSCy Schubert static int
load_nameservers_from_registry(struct evdns_base * base)38692b15cb3dSCy Schubert load_nameservers_from_registry(struct evdns_base *base)
38702b15cb3dSCy Schubert {
38712b15cb3dSCy Schubert 	int found = 0;
38722b15cb3dSCy Schubert 	int r;
38732b15cb3dSCy Schubert #define TRY(k, name) \
38742b15cb3dSCy Schubert 	if (!found && config_nameserver_from_reg_key(base,k,TEXT(name)) == 0) { \
38752b15cb3dSCy Schubert 		log(EVDNS_LOG_DEBUG,"Found nameservers in %s/%s",#k,name); \
38762b15cb3dSCy Schubert 		found = 1;						\
38772b15cb3dSCy Schubert 	} else if (!found) {						\
38782b15cb3dSCy Schubert 		log(EVDNS_LOG_DEBUG,"Didn't find nameservers in %s/%s", \
38792b15cb3dSCy Schubert 		    #k,#name);						\
38802b15cb3dSCy Schubert 	}
38812b15cb3dSCy Schubert 
38822b15cb3dSCy Schubert 	ASSERT_LOCKED(base);
38832b15cb3dSCy Schubert 
38842b15cb3dSCy Schubert 	if (((int)GetVersion()) > 0) { /* NT */
38852b15cb3dSCy Schubert 		HKEY nt_key = 0, interfaces_key = 0;
38862b15cb3dSCy Schubert 
38872b15cb3dSCy Schubert 		if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0,
38882b15cb3dSCy Schubert 				 KEY_READ, &nt_key) != ERROR_SUCCESS) {
38892b15cb3dSCy Schubert 			log(EVDNS_LOG_DEBUG,"Couldn't open nt key, %d",(int)GetLastError());
38902b15cb3dSCy Schubert 			return -1;
38912b15cb3dSCy Schubert 		}
38922b15cb3dSCy Schubert 		r = RegOpenKeyEx(nt_key, TEXT("Interfaces"), 0,
38932b15cb3dSCy Schubert 			     KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS,
38942b15cb3dSCy Schubert 			     &interfaces_key);
38952b15cb3dSCy Schubert 		if (r != ERROR_SUCCESS) {
38962b15cb3dSCy Schubert 			log(EVDNS_LOG_DEBUG,"Couldn't open interfaces key, %d",(int)GetLastError());
38972b15cb3dSCy Schubert 			return -1;
38982b15cb3dSCy Schubert 		}
38992b15cb3dSCy Schubert 		TRY(nt_key, "NameServer");
39002b15cb3dSCy Schubert 		TRY(nt_key, "DhcpNameServer");
39012b15cb3dSCy Schubert 		TRY(interfaces_key, "NameServer");
39022b15cb3dSCy Schubert 		TRY(interfaces_key, "DhcpNameServer");
39032b15cb3dSCy Schubert 		RegCloseKey(interfaces_key);
39042b15cb3dSCy Schubert 		RegCloseKey(nt_key);
39052b15cb3dSCy Schubert 	} else {
39062b15cb3dSCy Schubert 		HKEY win_key = 0;
39072b15cb3dSCy Schubert 		if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_9X_KEY, 0,
39082b15cb3dSCy Schubert 				 KEY_READ, &win_key) != ERROR_SUCCESS) {
39092b15cb3dSCy Schubert 			log(EVDNS_LOG_DEBUG, "Couldn't open registry key, %d", (int)GetLastError());
39102b15cb3dSCy Schubert 			return -1;
39112b15cb3dSCy Schubert 		}
39122b15cb3dSCy Schubert 		TRY(win_key, "NameServer");
39132b15cb3dSCy Schubert 		RegCloseKey(win_key);
39142b15cb3dSCy Schubert 	}
39152b15cb3dSCy Schubert 
39162b15cb3dSCy Schubert 	if (found == 0) {
39172b15cb3dSCy Schubert 		log(EVDNS_LOG_WARN,"Didn't find any nameservers.");
39182b15cb3dSCy Schubert 	}
39192b15cb3dSCy Schubert 
39202b15cb3dSCy Schubert 	return found ? 0 : -1;
39212b15cb3dSCy Schubert #undef TRY
39222b15cb3dSCy Schubert }
39232b15cb3dSCy Schubert 
39242b15cb3dSCy Schubert int
evdns_base_config_windows_nameservers(struct evdns_base * base)39252b15cb3dSCy Schubert evdns_base_config_windows_nameservers(struct evdns_base *base)
39262b15cb3dSCy Schubert {
39272b15cb3dSCy Schubert 	int r;
39282b15cb3dSCy Schubert 	char *fname;
39292b15cb3dSCy Schubert 	if (base == NULL)
39302b15cb3dSCy Schubert 		base = current_base;
39312b15cb3dSCy Schubert 	if (base == NULL)
39322b15cb3dSCy Schubert 		return -1;
39332b15cb3dSCy Schubert 	EVDNS_LOCK(base);
3934a25439b6SCy Schubert 	fname = evdns_get_default_hosts_filename();
3935a25439b6SCy Schubert 	log(EVDNS_LOG_DEBUG, "Loading hosts entries from %s", fname);
3936a25439b6SCy Schubert 	evdns_base_load_hosts(base, fname);
3937a25439b6SCy Schubert 	if (fname)
3938a25439b6SCy Schubert 		mm_free(fname);
3939a25439b6SCy Schubert 
39402b15cb3dSCy Schubert 	if (load_nameservers_with_getnetworkparams(base) == 0) {
39412b15cb3dSCy Schubert 		EVDNS_UNLOCK(base);
39422b15cb3dSCy Schubert 		return 0;
39432b15cb3dSCy Schubert 	}
39442b15cb3dSCy Schubert 	r = load_nameservers_from_registry(base);
39452b15cb3dSCy Schubert 
39462b15cb3dSCy Schubert 	EVDNS_UNLOCK(base);
39472b15cb3dSCy Schubert 	return r;
39482b15cb3dSCy Schubert }
39492b15cb3dSCy Schubert 
39502b15cb3dSCy Schubert int
evdns_config_windows_nameservers(void)39512b15cb3dSCy Schubert evdns_config_windows_nameservers(void)
39522b15cb3dSCy Schubert {
39532b15cb3dSCy Schubert 	if (!current_base) {
39542b15cb3dSCy Schubert 		current_base = evdns_base_new(NULL, 1);
39552b15cb3dSCy Schubert 		return current_base == NULL ? -1 : 0;
39562b15cb3dSCy Schubert 	} else {
39572b15cb3dSCy Schubert 		return evdns_base_config_windows_nameservers(current_base);
39582b15cb3dSCy Schubert 	}
39592b15cb3dSCy Schubert }
39602b15cb3dSCy Schubert #endif
39612b15cb3dSCy Schubert 
39622b15cb3dSCy Schubert struct evdns_base *
evdns_base_new(struct event_base * event_base,int flags)39632b15cb3dSCy Schubert evdns_base_new(struct event_base *event_base, int flags)
39642b15cb3dSCy Schubert {
39652b15cb3dSCy Schubert 	struct evdns_base *base;
39662b15cb3dSCy Schubert 
39672b15cb3dSCy Schubert 	if (evutil_secure_rng_init() < 0) {
39682b15cb3dSCy Schubert 		log(EVDNS_LOG_WARN, "Unable to seed random number generator; "
39692b15cb3dSCy Schubert 		    "DNS can't run.");
39702b15cb3dSCy Schubert 		return NULL;
39712b15cb3dSCy Schubert 	}
39722b15cb3dSCy Schubert 
39732b15cb3dSCy Schubert 	/* Give the evutil library a hook into its evdns-enabled
39742b15cb3dSCy Schubert 	 * functionality.  We can't just call evdns_getaddrinfo directly or
39752b15cb3dSCy Schubert 	 * else libevent-core will depend on libevent-extras. */
39762b15cb3dSCy Schubert 	evutil_set_evdns_getaddrinfo_fn_(evdns_getaddrinfo);
3977*a466cc55SCy Schubert 	evutil_set_evdns_getaddrinfo_cancel_fn_(evdns_getaddrinfo_cancel);
39782b15cb3dSCy Schubert 
39792b15cb3dSCy Schubert 	base = mm_malloc(sizeof(struct evdns_base));
39802b15cb3dSCy Schubert 	if (base == NULL)
39812b15cb3dSCy Schubert 		return (NULL);
39822b15cb3dSCy Schubert 	memset(base, 0, sizeof(struct evdns_base));
39832b15cb3dSCy Schubert 	base->req_waiting_head = NULL;
39842b15cb3dSCy Schubert 
39852b15cb3dSCy Schubert 	EVTHREAD_ALLOC_LOCK(base->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
39862b15cb3dSCy Schubert 	EVDNS_LOCK(base);
39872b15cb3dSCy Schubert 
39882b15cb3dSCy Schubert 	/* Set max requests inflight and allocate req_heads. */
39892b15cb3dSCy Schubert 	base->req_heads = NULL;
39902b15cb3dSCy Schubert 
39912b15cb3dSCy Schubert 	evdns_base_set_max_requests_inflight(base, 64);
39922b15cb3dSCy Schubert 
39932b15cb3dSCy Schubert 	base->server_head = NULL;
39942b15cb3dSCy Schubert 	base->event_base = event_base;
39952b15cb3dSCy Schubert 	base->global_good_nameservers = base->global_requests_inflight =
39962b15cb3dSCy Schubert 		base->global_requests_waiting = 0;
39972b15cb3dSCy Schubert 
39982b15cb3dSCy Schubert 	base->global_timeout.tv_sec = 5;
39992b15cb3dSCy Schubert 	base->global_timeout.tv_usec = 0;
40002b15cb3dSCy Schubert 	base->global_max_reissues = 1;
40012b15cb3dSCy Schubert 	base->global_max_retransmits = 3;
40022b15cb3dSCy Schubert 	base->global_max_nameserver_timeout = 3;
40032b15cb3dSCy Schubert 	base->global_search_state = NULL;
40042b15cb3dSCy Schubert 	base->global_randomize_case = 1;
40052b15cb3dSCy Schubert 	base->global_getaddrinfo_allow_skew.tv_sec = 3;
40062b15cb3dSCy Schubert 	base->global_getaddrinfo_allow_skew.tv_usec = 0;
40072b15cb3dSCy Schubert 	base->global_nameserver_probe_initial_timeout.tv_sec = 10;
40082b15cb3dSCy Schubert 	base->global_nameserver_probe_initial_timeout.tv_usec = 0;
40092b15cb3dSCy Schubert 
40102b15cb3dSCy Schubert 	TAILQ_INIT(&base->hostsdb);
40112b15cb3dSCy Schubert 
4012*a466cc55SCy Schubert #define EVDNS_BASE_ALL_FLAGS ( \
4013*a466cc55SCy Schubert 	EVDNS_BASE_INITIALIZE_NAMESERVERS | \
4014*a466cc55SCy Schubert 	EVDNS_BASE_DISABLE_WHEN_INACTIVE  | \
4015*a466cc55SCy Schubert 	EVDNS_BASE_NAMESERVERS_NO_DEFAULT | \
4016*a466cc55SCy Schubert 	0)
4017*a466cc55SCy Schubert 
40182b15cb3dSCy Schubert 	if (flags & ~EVDNS_BASE_ALL_FLAGS) {
40192b15cb3dSCy Schubert 		flags = EVDNS_BASE_INITIALIZE_NAMESERVERS;
40202b15cb3dSCy Schubert 		log(EVDNS_LOG_WARN,
40212b15cb3dSCy Schubert 		    "Unrecognized flag passed to evdns_base_new(). Assuming "
40222b15cb3dSCy Schubert 		    "you meant EVDNS_BASE_INITIALIZE_NAMESERVERS.");
40232b15cb3dSCy Schubert 	}
40242b15cb3dSCy Schubert #undef EVDNS_BASE_ALL_FLAGS
40252b15cb3dSCy Schubert 
40262b15cb3dSCy Schubert 	if (flags & EVDNS_BASE_INITIALIZE_NAMESERVERS) {
40272b15cb3dSCy Schubert 		int r;
4028*a466cc55SCy Schubert 		int opts = DNS_OPTIONS_ALL;
4029*a466cc55SCy Schubert 		if (flags & EVDNS_BASE_NAMESERVERS_NO_DEFAULT) {
4030*a466cc55SCy Schubert 			opts |= DNS_OPTION_NAMESERVERS_NO_DEFAULT;
4031*a466cc55SCy Schubert 		}
4032*a466cc55SCy Schubert 
40332b15cb3dSCy Schubert #ifdef _WIN32
40342b15cb3dSCy Schubert 		r = evdns_base_config_windows_nameservers(base);
40352b15cb3dSCy Schubert #else
4036*a466cc55SCy Schubert 		r = evdns_base_resolv_conf_parse(base, opts, "/etc/resolv.conf");
40372b15cb3dSCy Schubert #endif
4038*a466cc55SCy Schubert 		if (r) {
40392b15cb3dSCy Schubert 			evdns_base_free_and_unlock(base, 0);
40402b15cb3dSCy Schubert 			return NULL;
40412b15cb3dSCy Schubert 		}
40422b15cb3dSCy Schubert 	}
40432b15cb3dSCy Schubert 	if (flags & EVDNS_BASE_DISABLE_WHEN_INACTIVE) {
40442b15cb3dSCy Schubert 		base->disable_when_inactive = 1;
40452b15cb3dSCy Schubert 	}
40462b15cb3dSCy Schubert 
40472b15cb3dSCy Schubert 	EVDNS_UNLOCK(base);
40482b15cb3dSCy Schubert 	return base;
40492b15cb3dSCy Schubert }
40502b15cb3dSCy Schubert 
40512b15cb3dSCy Schubert int
evdns_init(void)40522b15cb3dSCy Schubert evdns_init(void)
40532b15cb3dSCy Schubert {
40542b15cb3dSCy Schubert 	struct evdns_base *base = evdns_base_new(NULL, 1);
40552b15cb3dSCy Schubert 	if (base) {
40562b15cb3dSCy Schubert 		current_base = base;
40572b15cb3dSCy Schubert 		return 0;
40582b15cb3dSCy Schubert 	} else {
40592b15cb3dSCy Schubert 		return -1;
40602b15cb3dSCy Schubert 	}
40612b15cb3dSCy Schubert }
40622b15cb3dSCy Schubert 
40632b15cb3dSCy Schubert const char *
evdns_err_to_string(int err)40642b15cb3dSCy Schubert evdns_err_to_string(int err)
40652b15cb3dSCy Schubert {
40662b15cb3dSCy Schubert     switch (err) {
40672b15cb3dSCy Schubert 	case DNS_ERR_NONE: return "no error";
40682b15cb3dSCy Schubert 	case DNS_ERR_FORMAT: return "misformatted query";
40692b15cb3dSCy Schubert 	case DNS_ERR_SERVERFAILED: return "server failed";
40702b15cb3dSCy Schubert 	case DNS_ERR_NOTEXIST: return "name does not exist";
40712b15cb3dSCy Schubert 	case DNS_ERR_NOTIMPL: return "query not implemented";
40722b15cb3dSCy Schubert 	case DNS_ERR_REFUSED: return "refused";
40732b15cb3dSCy Schubert 
40742b15cb3dSCy Schubert 	case DNS_ERR_TRUNCATED: return "reply truncated or ill-formed";
40752b15cb3dSCy Schubert 	case DNS_ERR_UNKNOWN: return "unknown";
40762b15cb3dSCy Schubert 	case DNS_ERR_TIMEOUT: return "request timed out";
40772b15cb3dSCy Schubert 	case DNS_ERR_SHUTDOWN: return "dns subsystem shut down";
40782b15cb3dSCy Schubert 	case DNS_ERR_CANCEL: return "dns request canceled";
40792b15cb3dSCy Schubert 	case DNS_ERR_NODATA: return "no records in the reply";
40802b15cb3dSCy Schubert 	default: return "[Unknown error code]";
40812b15cb3dSCy Schubert     }
40822b15cb3dSCy Schubert }
40832b15cb3dSCy Schubert 
40842b15cb3dSCy Schubert static void
evdns_nameserver_free(struct nameserver * server)40852b15cb3dSCy Schubert evdns_nameserver_free(struct nameserver *server)
40862b15cb3dSCy Schubert {
40872b15cb3dSCy Schubert 	if (server->socket >= 0)
40882b15cb3dSCy Schubert 		evutil_closesocket(server->socket);
40892b15cb3dSCy Schubert 	(void) event_del(&server->event);
40902b15cb3dSCy Schubert 	event_debug_unassign(&server->event);
40912b15cb3dSCy Schubert 	if (server->state == 0)
40922b15cb3dSCy Schubert 		(void) event_del(&server->timeout_event);
4093a25439b6SCy Schubert 	if (server->probe_request) {
4094a25439b6SCy Schubert 		evdns_cancel_request(server->base, server->probe_request);
4095a25439b6SCy Schubert 		server->probe_request = NULL;
4096a25439b6SCy Schubert 	}
40972b15cb3dSCy Schubert 	event_debug_unassign(&server->timeout_event);
40982b15cb3dSCy Schubert 	mm_free(server);
40992b15cb3dSCy Schubert }
41002b15cb3dSCy Schubert 
41012b15cb3dSCy Schubert static void
evdns_base_free_and_unlock(struct evdns_base * base,int fail_requests)41022b15cb3dSCy Schubert evdns_base_free_and_unlock(struct evdns_base *base, int fail_requests)
41032b15cb3dSCy Schubert {
41042b15cb3dSCy Schubert 	struct nameserver *server, *server_next;
41052b15cb3dSCy Schubert 	struct search_domain *dom, *dom_next;
41062b15cb3dSCy Schubert 	int i;
41072b15cb3dSCy Schubert 
41082b15cb3dSCy Schubert 	/* Requires that we hold the lock. */
41092b15cb3dSCy Schubert 
41102b15cb3dSCy Schubert 	/* TODO(nickm) we might need to refcount here. */
41112b15cb3dSCy Schubert 
4112*a466cc55SCy Schubert 	while (base->req_waiting_head) {
4113*a466cc55SCy Schubert 		if (fail_requests)
4114*a466cc55SCy Schubert 			reply_schedule_callback(base->req_waiting_head, 0, DNS_ERR_SHUTDOWN, NULL);
4115*a466cc55SCy Schubert 		request_finished(base->req_waiting_head, &base->req_waiting_head, 1);
4116a25439b6SCy Schubert 	}
41172b15cb3dSCy Schubert 	for (i = 0; i < base->n_req_heads; ++i) {
41182b15cb3dSCy Schubert 		while (base->req_heads[i]) {
41192b15cb3dSCy Schubert 			if (fail_requests)
41202b15cb3dSCy Schubert 				reply_schedule_callback(base->req_heads[i], 0, DNS_ERR_SHUTDOWN, NULL);
41212b15cb3dSCy Schubert 			request_finished(base->req_heads[i], &REQ_HEAD(base, base->req_heads[i]->trans_id), 1);
41222b15cb3dSCy Schubert 		}
41232b15cb3dSCy Schubert 	}
41242b15cb3dSCy Schubert 	base->global_requests_inflight = base->global_requests_waiting = 0;
41252b15cb3dSCy Schubert 
4126*a466cc55SCy Schubert 	for (server = base->server_head; server; server = server_next) {
4127*a466cc55SCy Schubert 		server_next = server->next;
4128*a466cc55SCy Schubert 		/** already done something before */
4129*a466cc55SCy Schubert 		server->probe_request = NULL;
4130*a466cc55SCy Schubert 		evdns_nameserver_free(server);
4131*a466cc55SCy Schubert 		if (server_next == base->server_head)
4132*a466cc55SCy Schubert 			break;
4133*a466cc55SCy Schubert 	}
4134*a466cc55SCy Schubert 	base->server_head = NULL;
4135*a466cc55SCy Schubert 	base->global_good_nameservers = 0;
41362b15cb3dSCy Schubert 
41372b15cb3dSCy Schubert 	if (base->global_search_state) {
41382b15cb3dSCy Schubert 		for (dom = base->global_search_state->head; dom; dom = dom_next) {
41392b15cb3dSCy Schubert 			dom_next = dom->next;
41402b15cb3dSCy Schubert 			mm_free(dom);
41412b15cb3dSCy Schubert 		}
41422b15cb3dSCy Schubert 		mm_free(base->global_search_state);
41432b15cb3dSCy Schubert 		base->global_search_state = NULL;
41442b15cb3dSCy Schubert 	}
41452b15cb3dSCy Schubert 
41462b15cb3dSCy Schubert 	{
41472b15cb3dSCy Schubert 		struct hosts_entry *victim;
41482b15cb3dSCy Schubert 		while ((victim = TAILQ_FIRST(&base->hostsdb))) {
41492b15cb3dSCy Schubert 			TAILQ_REMOVE(&base->hostsdb, victim, next);
41502b15cb3dSCy Schubert 			mm_free(victim);
41512b15cb3dSCy Schubert 		}
41522b15cb3dSCy Schubert 	}
41532b15cb3dSCy Schubert 
41542b15cb3dSCy Schubert 	mm_free(base->req_heads);
41552b15cb3dSCy Schubert 
41562b15cb3dSCy Schubert 	EVDNS_UNLOCK(base);
41572b15cb3dSCy Schubert 	EVTHREAD_FREE_LOCK(base->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
41582b15cb3dSCy Schubert 
41592b15cb3dSCy Schubert 	mm_free(base);
41602b15cb3dSCy Schubert }
41612b15cb3dSCy Schubert 
41622b15cb3dSCy Schubert void
evdns_base_free(struct evdns_base * base,int fail_requests)41632b15cb3dSCy Schubert evdns_base_free(struct evdns_base *base, int fail_requests)
41642b15cb3dSCy Schubert {
41652b15cb3dSCy Schubert 	EVDNS_LOCK(base);
41662b15cb3dSCy Schubert 	evdns_base_free_and_unlock(base, fail_requests);
41672b15cb3dSCy Schubert }
41682b15cb3dSCy Schubert 
41692b15cb3dSCy Schubert void
evdns_base_clear_host_addresses(struct evdns_base * base)41702b15cb3dSCy Schubert evdns_base_clear_host_addresses(struct evdns_base *base)
41712b15cb3dSCy Schubert {
41722b15cb3dSCy Schubert 	struct hosts_entry *victim;
41732b15cb3dSCy Schubert 	EVDNS_LOCK(base);
41742b15cb3dSCy Schubert 	while ((victim = TAILQ_FIRST(&base->hostsdb))) {
41752b15cb3dSCy Schubert 		TAILQ_REMOVE(&base->hostsdb, victim, next);
41762b15cb3dSCy Schubert 		mm_free(victim);
41772b15cb3dSCy Schubert 	}
41782b15cb3dSCy Schubert 	EVDNS_UNLOCK(base);
41792b15cb3dSCy Schubert }
41802b15cb3dSCy Schubert 
41812b15cb3dSCy Schubert void
evdns_shutdown(int fail_requests)41822b15cb3dSCy Schubert evdns_shutdown(int fail_requests)
41832b15cb3dSCy Schubert {
41842b15cb3dSCy Schubert 	if (current_base) {
41852b15cb3dSCy Schubert 		struct evdns_base *b = current_base;
41862b15cb3dSCy Schubert 		current_base = NULL;
41872b15cb3dSCy Schubert 		evdns_base_free(b, fail_requests);
41882b15cb3dSCy Schubert 	}
41892b15cb3dSCy Schubert 	evdns_log_fn = NULL;
41902b15cb3dSCy Schubert }
41912b15cb3dSCy Schubert 
41922b15cb3dSCy Schubert static int
evdns_base_parse_hosts_line(struct evdns_base * base,char * line)41932b15cb3dSCy Schubert evdns_base_parse_hosts_line(struct evdns_base *base, char *line)
41942b15cb3dSCy Schubert {
41952b15cb3dSCy Schubert 	char *strtok_state;
41962b15cb3dSCy Schubert 	static const char *const delims = " \t";
41972b15cb3dSCy Schubert 	char *const addr = strtok_r(line, delims, &strtok_state);
41982b15cb3dSCy Schubert 	char *hostname, *hash;
41992b15cb3dSCy Schubert 	struct sockaddr_storage ss;
42002b15cb3dSCy Schubert 	int socklen = sizeof(ss);
42012b15cb3dSCy Schubert 	ASSERT_LOCKED(base);
42022b15cb3dSCy Schubert 
42032b15cb3dSCy Schubert #define NEXT_TOKEN strtok_r(NULL, delims, &strtok_state)
42042b15cb3dSCy Schubert 
42052b15cb3dSCy Schubert 	if (!addr || *addr == '#')
42062b15cb3dSCy Schubert 		return 0;
42072b15cb3dSCy Schubert 
42082b15cb3dSCy Schubert 	memset(&ss, 0, sizeof(ss));
42092b15cb3dSCy Schubert 	if (evutil_parse_sockaddr_port(addr, (struct sockaddr*)&ss, &socklen)<0)
42102b15cb3dSCy Schubert 		return -1;
42112b15cb3dSCy Schubert 	if (socklen > (int)sizeof(struct sockaddr_in6))
42122b15cb3dSCy Schubert 		return -1;
42132b15cb3dSCy Schubert 
42142b15cb3dSCy Schubert 	if (sockaddr_getport((struct sockaddr*)&ss))
42152b15cb3dSCy Schubert 		return -1;
42162b15cb3dSCy Schubert 
42172b15cb3dSCy Schubert 	while ((hostname = NEXT_TOKEN)) {
42182b15cb3dSCy Schubert 		struct hosts_entry *he;
42192b15cb3dSCy Schubert 		size_t namelen;
42202b15cb3dSCy Schubert 		if ((hash = strchr(hostname, '#'))) {
42212b15cb3dSCy Schubert 			if (hash == hostname)
42222b15cb3dSCy Schubert 				return 0;
42232b15cb3dSCy Schubert 			*hash = '\0';
42242b15cb3dSCy Schubert 		}
42252b15cb3dSCy Schubert 
42262b15cb3dSCy Schubert 		namelen = strlen(hostname);
42272b15cb3dSCy Schubert 
42282b15cb3dSCy Schubert 		he = mm_calloc(1, sizeof(struct hosts_entry)+namelen);
42292b15cb3dSCy Schubert 		if (!he)
42302b15cb3dSCy Schubert 			return -1;
42312b15cb3dSCy Schubert 		EVUTIL_ASSERT(socklen <= (int)sizeof(he->addr));
42322b15cb3dSCy Schubert 		memcpy(&he->addr, &ss, socklen);
42332b15cb3dSCy Schubert 		memcpy(he->hostname, hostname, namelen+1);
42342b15cb3dSCy Schubert 		he->addrlen = socklen;
42352b15cb3dSCy Schubert 
42362b15cb3dSCy Schubert 		TAILQ_INSERT_TAIL(&base->hostsdb, he, next);
42372b15cb3dSCy Schubert 
42382b15cb3dSCy Schubert 		if (hash)
42392b15cb3dSCy Schubert 			return 0;
42402b15cb3dSCy Schubert 	}
42412b15cb3dSCy Schubert 
42422b15cb3dSCy Schubert 	return 0;
42432b15cb3dSCy Schubert #undef NEXT_TOKEN
42442b15cb3dSCy Schubert }
42452b15cb3dSCy Schubert 
42462b15cb3dSCy Schubert static int
evdns_base_load_hosts_impl(struct evdns_base * base,const char * hosts_fname)42472b15cb3dSCy Schubert evdns_base_load_hosts_impl(struct evdns_base *base, const char *hosts_fname)
42482b15cb3dSCy Schubert {
42492b15cb3dSCy Schubert 	char *str=NULL, *cp, *eol;
42502b15cb3dSCy Schubert 	size_t len;
42512b15cb3dSCy Schubert 	int err=0;
42522b15cb3dSCy Schubert 
42532b15cb3dSCy Schubert 	ASSERT_LOCKED(base);
42542b15cb3dSCy Schubert 
42552b15cb3dSCy Schubert 	if (hosts_fname == NULL ||
42562b15cb3dSCy Schubert 	    (err = evutil_read_file_(hosts_fname, &str, &len, 0)) < 0) {
42572b15cb3dSCy Schubert 		char tmp[64];
42582b15cb3dSCy Schubert 		strlcpy(tmp, "127.0.0.1   localhost", sizeof(tmp));
42592b15cb3dSCy Schubert 		evdns_base_parse_hosts_line(base, tmp);
42602b15cb3dSCy Schubert 		strlcpy(tmp, "::1   localhost", sizeof(tmp));
42612b15cb3dSCy Schubert 		evdns_base_parse_hosts_line(base, tmp);
42622b15cb3dSCy Schubert 		return err ? -1 : 0;
42632b15cb3dSCy Schubert 	}
42642b15cb3dSCy Schubert 
42652b15cb3dSCy Schubert 	/* This will break early if there is a NUL in the hosts file.
42662b15cb3dSCy Schubert 	 * Probably not a problem.*/
42672b15cb3dSCy Schubert 	cp = str;
42682b15cb3dSCy Schubert 	for (;;) {
42692b15cb3dSCy Schubert 		eol = strchr(cp, '\n');
42702b15cb3dSCy Schubert 
42712b15cb3dSCy Schubert 		if (eol) {
42722b15cb3dSCy Schubert 			*eol = '\0';
42732b15cb3dSCy Schubert 			evdns_base_parse_hosts_line(base, cp);
42742b15cb3dSCy Schubert 			cp = eol+1;
42752b15cb3dSCy Schubert 		} else {
42762b15cb3dSCy Schubert 			evdns_base_parse_hosts_line(base, cp);
42772b15cb3dSCy Schubert 			break;
42782b15cb3dSCy Schubert 		}
42792b15cb3dSCy Schubert 	}
42802b15cb3dSCy Schubert 
42812b15cb3dSCy Schubert 	mm_free(str);
42822b15cb3dSCy Schubert 	return 0;
42832b15cb3dSCy Schubert }
42842b15cb3dSCy Schubert 
42852b15cb3dSCy Schubert int
evdns_base_load_hosts(struct evdns_base * base,const char * hosts_fname)42862b15cb3dSCy Schubert evdns_base_load_hosts(struct evdns_base *base, const char *hosts_fname)
42872b15cb3dSCy Schubert {
42882b15cb3dSCy Schubert 	int res;
42892b15cb3dSCy Schubert 	if (!base)
42902b15cb3dSCy Schubert 		base = current_base;
42912b15cb3dSCy Schubert 	EVDNS_LOCK(base);
42922b15cb3dSCy Schubert 	res = evdns_base_load_hosts_impl(base, hosts_fname);
42932b15cb3dSCy Schubert 	EVDNS_UNLOCK(base);
42942b15cb3dSCy Schubert 	return res;
42952b15cb3dSCy Schubert }
42962b15cb3dSCy Schubert 
42972b15cb3dSCy Schubert /* A single request for a getaddrinfo, either v4 or v6. */
42982b15cb3dSCy Schubert struct getaddrinfo_subrequest {
42992b15cb3dSCy Schubert 	struct evdns_request *r;
43002b15cb3dSCy Schubert 	ev_uint32_t type;
43012b15cb3dSCy Schubert };
43022b15cb3dSCy Schubert 
43032b15cb3dSCy Schubert /* State data used to implement an in-progress getaddrinfo. */
43042b15cb3dSCy Schubert struct evdns_getaddrinfo_request {
43052b15cb3dSCy Schubert 	struct evdns_base *evdns_base;
43062b15cb3dSCy Schubert 	/* Copy of the modified 'hints' data that we'll use to build
43072b15cb3dSCy Schubert 	 * answers. */
43082b15cb3dSCy Schubert 	struct evutil_addrinfo hints;
43092b15cb3dSCy Schubert 	/* The callback to invoke when we're done */
43102b15cb3dSCy Schubert 	evdns_getaddrinfo_cb user_cb;
43112b15cb3dSCy Schubert 	/* User-supplied data to give to the callback. */
43122b15cb3dSCy Schubert 	void *user_data;
43132b15cb3dSCy Schubert 	/* The port to use when building sockaddrs. */
43142b15cb3dSCy Schubert 	ev_uint16_t port;
43152b15cb3dSCy Schubert 	/* The sub_request for an A record (if any) */
43162b15cb3dSCy Schubert 	struct getaddrinfo_subrequest ipv4_request;
43172b15cb3dSCy Schubert 	/* The sub_request for an AAAA record (if any) */
43182b15cb3dSCy Schubert 	struct getaddrinfo_subrequest ipv6_request;
43192b15cb3dSCy Schubert 
43202b15cb3dSCy Schubert 	/* The cname result that we were told (if any) */
43212b15cb3dSCy Schubert 	char *cname_result;
43222b15cb3dSCy Schubert 
43232b15cb3dSCy Schubert 	/* If we have one request answered and one request still inflight,
43242b15cb3dSCy Schubert 	 * then this field holds the answer from the first request... */
43252b15cb3dSCy Schubert 	struct evutil_addrinfo *pending_result;
43262b15cb3dSCy Schubert 	/* And this event is a timeout that will tell us to cancel the second
43272b15cb3dSCy Schubert 	 * request if it's taking a long time. */
43282b15cb3dSCy Schubert 	struct event timeout;
43292b15cb3dSCy Schubert 
43302b15cb3dSCy Schubert 	/* And this field holds the error code from the first request... */
43312b15cb3dSCy Schubert 	int pending_error;
43322b15cb3dSCy Schubert 	/* If this is set, the user canceled this request. */
43332b15cb3dSCy Schubert 	unsigned user_canceled : 1;
43342b15cb3dSCy Schubert 	/* If this is set, the user can no longer cancel this request; we're
43352b15cb3dSCy Schubert 	 * just waiting for the free. */
43362b15cb3dSCy Schubert 	unsigned request_done : 1;
43372b15cb3dSCy Schubert };
43382b15cb3dSCy Schubert 
43392b15cb3dSCy Schubert /* Convert an evdns errors to the equivalent getaddrinfo error. */
43402b15cb3dSCy Schubert static int
evdns_err_to_getaddrinfo_err(int e1)43412b15cb3dSCy Schubert evdns_err_to_getaddrinfo_err(int e1)
43422b15cb3dSCy Schubert {
43432b15cb3dSCy Schubert 	/* XXX Do this better! */
43442b15cb3dSCy Schubert 	if (e1 == DNS_ERR_NONE)
43452b15cb3dSCy Schubert 		return 0;
43462b15cb3dSCy Schubert 	else if (e1 == DNS_ERR_NOTEXIST)
43472b15cb3dSCy Schubert 		return EVUTIL_EAI_NONAME;
43482b15cb3dSCy Schubert 	else
43492b15cb3dSCy Schubert 		return EVUTIL_EAI_FAIL;
43502b15cb3dSCy Schubert }
43512b15cb3dSCy Schubert 
43522b15cb3dSCy Schubert /* Return the more informative of two getaddrinfo errors. */
43532b15cb3dSCy Schubert static int
getaddrinfo_merge_err(int e1,int e2)43542b15cb3dSCy Schubert getaddrinfo_merge_err(int e1, int e2)
43552b15cb3dSCy Schubert {
43562b15cb3dSCy Schubert 	/* XXXX be cleverer here. */
43572b15cb3dSCy Schubert 	if (e1 == 0)
43582b15cb3dSCy Schubert 		return e2;
43592b15cb3dSCy Schubert 	else
43602b15cb3dSCy Schubert 		return e1;
43612b15cb3dSCy Schubert }
43622b15cb3dSCy Schubert 
43632b15cb3dSCy Schubert static void
free_getaddrinfo_request(struct evdns_getaddrinfo_request * data)43642b15cb3dSCy Schubert free_getaddrinfo_request(struct evdns_getaddrinfo_request *data)
43652b15cb3dSCy Schubert {
43662b15cb3dSCy Schubert 	/* DO NOT CALL this if either of the requests is pending.  Only once
43672b15cb3dSCy Schubert 	 * both callbacks have been invoked is it safe to free the request */
43682b15cb3dSCy Schubert 	if (data->pending_result)
43692b15cb3dSCy Schubert 		evutil_freeaddrinfo(data->pending_result);
43702b15cb3dSCy Schubert 	if (data->cname_result)
43712b15cb3dSCy Schubert 		mm_free(data->cname_result);
43722b15cb3dSCy Schubert 	event_del(&data->timeout);
43732b15cb3dSCy Schubert 	mm_free(data);
43742b15cb3dSCy Schubert 	return;
43752b15cb3dSCy Schubert }
43762b15cb3dSCy Schubert 
43772b15cb3dSCy Schubert static void
add_cname_to_reply(struct evdns_getaddrinfo_request * data,struct evutil_addrinfo * ai)43782b15cb3dSCy Schubert add_cname_to_reply(struct evdns_getaddrinfo_request *data,
43792b15cb3dSCy Schubert     struct evutil_addrinfo *ai)
43802b15cb3dSCy Schubert {
43812b15cb3dSCy Schubert 	if (data->cname_result && ai) {
43822b15cb3dSCy Schubert 		ai->ai_canonname = data->cname_result;
43832b15cb3dSCy Schubert 		data->cname_result = NULL;
43842b15cb3dSCy Schubert 	}
43852b15cb3dSCy Schubert }
43862b15cb3dSCy Schubert 
43872b15cb3dSCy Schubert /* Callback: invoked when one request in a mixed-format A/AAAA getaddrinfo
43882b15cb3dSCy Schubert  * request has finished, but the other one took too long to answer. Pass
43892b15cb3dSCy Schubert  * along the answer we got, and cancel the other request.
43902b15cb3dSCy Schubert  */
43912b15cb3dSCy Schubert static void
evdns_getaddrinfo_timeout_cb(evutil_socket_t fd,short what,void * ptr)43922b15cb3dSCy Schubert evdns_getaddrinfo_timeout_cb(evutil_socket_t fd, short what, void *ptr)
43932b15cb3dSCy Schubert {
43942b15cb3dSCy Schubert 	int v4_timedout = 0, v6_timedout = 0;
43952b15cb3dSCy Schubert 	struct evdns_getaddrinfo_request *data = ptr;
43962b15cb3dSCy Schubert 
43972b15cb3dSCy Schubert 	/* Cancel any pending requests, and note which one */
43982b15cb3dSCy Schubert 	if (data->ipv4_request.r) {
43992b15cb3dSCy Schubert 		/* XXXX This does nothing if the request's callback is already
44002b15cb3dSCy Schubert 		 * running (pending_cb is set). */
44012b15cb3dSCy Schubert 		evdns_cancel_request(NULL, data->ipv4_request.r);
44022b15cb3dSCy Schubert 		v4_timedout = 1;
44032b15cb3dSCy Schubert 		EVDNS_LOCK(data->evdns_base);
44042b15cb3dSCy Schubert 		++data->evdns_base->getaddrinfo_ipv4_timeouts;
44052b15cb3dSCy Schubert 		EVDNS_UNLOCK(data->evdns_base);
44062b15cb3dSCy Schubert 	}
44072b15cb3dSCy Schubert 	if (data->ipv6_request.r) {
44082b15cb3dSCy Schubert 		/* XXXX This does nothing if the request's callback is already
44092b15cb3dSCy Schubert 		 * running (pending_cb is set). */
44102b15cb3dSCy Schubert 		evdns_cancel_request(NULL, data->ipv6_request.r);
44112b15cb3dSCy Schubert 		v6_timedout = 1;
44122b15cb3dSCy Schubert 		EVDNS_LOCK(data->evdns_base);
44132b15cb3dSCy Schubert 		++data->evdns_base->getaddrinfo_ipv6_timeouts;
44142b15cb3dSCy Schubert 		EVDNS_UNLOCK(data->evdns_base);
44152b15cb3dSCy Schubert 	}
44162b15cb3dSCy Schubert 
44172b15cb3dSCy Schubert 	/* We only use this timeout callback when we have an answer for
44182b15cb3dSCy Schubert 	 * one address. */
44192b15cb3dSCy Schubert 	EVUTIL_ASSERT(!v4_timedout || !v6_timedout);
44202b15cb3dSCy Schubert 
44212b15cb3dSCy Schubert 	/* Report the outcome of the other request that didn't time out. */
44222b15cb3dSCy Schubert 	if (data->pending_result) {
44232b15cb3dSCy Schubert 		add_cname_to_reply(data, data->pending_result);
44242b15cb3dSCy Schubert 		data->user_cb(0, data->pending_result, data->user_data);
44252b15cb3dSCy Schubert 		data->pending_result = NULL;
44262b15cb3dSCy Schubert 	} else {
44272b15cb3dSCy Schubert 		int e = data->pending_error;
44282b15cb3dSCy Schubert 		if (!e)
44292b15cb3dSCy Schubert 			e = EVUTIL_EAI_AGAIN;
44302b15cb3dSCy Schubert 		data->user_cb(e, NULL, data->user_data);
44312b15cb3dSCy Schubert 	}
44322b15cb3dSCy Schubert 
44332b15cb3dSCy Schubert 	data->user_cb = NULL; /* prevent double-call if evdns callbacks are
44342b15cb3dSCy Schubert 			       * in-progress. XXXX It would be better if this
44352b15cb3dSCy Schubert 			       * weren't necessary. */
44362b15cb3dSCy Schubert 
44372b15cb3dSCy Schubert 	if (!v4_timedout && !v6_timedout) {
44382b15cb3dSCy Schubert 		/* should be impossible? XXXX */
44392b15cb3dSCy Schubert 		free_getaddrinfo_request(data);
44402b15cb3dSCy Schubert 	}
44412b15cb3dSCy Schubert }
44422b15cb3dSCy Schubert 
44432b15cb3dSCy Schubert static int
evdns_getaddrinfo_set_timeout(struct evdns_base * evdns_base,struct evdns_getaddrinfo_request * data)44442b15cb3dSCy Schubert evdns_getaddrinfo_set_timeout(struct evdns_base *evdns_base,
44452b15cb3dSCy Schubert     struct evdns_getaddrinfo_request *data)
44462b15cb3dSCy Schubert {
44472b15cb3dSCy Schubert 	return event_add(&data->timeout, &evdns_base->global_getaddrinfo_allow_skew);
44482b15cb3dSCy Schubert }
44492b15cb3dSCy Schubert 
44502b15cb3dSCy Schubert static inline int
evdns_result_is_answer(int result)44512b15cb3dSCy Schubert evdns_result_is_answer(int result)
44522b15cb3dSCy Schubert {
44532b15cb3dSCy Schubert 	return (result != DNS_ERR_NOTIMPL && result != DNS_ERR_REFUSED &&
44542b15cb3dSCy Schubert 	    result != DNS_ERR_SERVERFAILED && result != DNS_ERR_CANCEL);
44552b15cb3dSCy Schubert }
44562b15cb3dSCy Schubert 
44572b15cb3dSCy Schubert static void
evdns_getaddrinfo_gotresolve(int result,char type,int count,int ttl,void * addresses,void * arg)44582b15cb3dSCy Schubert evdns_getaddrinfo_gotresolve(int result, char type, int count,
44592b15cb3dSCy Schubert     int ttl, void *addresses, void *arg)
44602b15cb3dSCy Schubert {
44612b15cb3dSCy Schubert 	int i;
44622b15cb3dSCy Schubert 	struct getaddrinfo_subrequest *req = arg;
44632b15cb3dSCy Schubert 	struct getaddrinfo_subrequest *other_req;
44642b15cb3dSCy Schubert 	struct evdns_getaddrinfo_request *data;
44652b15cb3dSCy Schubert 
44662b15cb3dSCy Schubert 	struct evutil_addrinfo *res;
44672b15cb3dSCy Schubert 
44682b15cb3dSCy Schubert 	struct sockaddr_in sin;
44692b15cb3dSCy Schubert 	struct sockaddr_in6 sin6;
44702b15cb3dSCy Schubert 	struct sockaddr *sa;
44712b15cb3dSCy Schubert 	int socklen, addrlen;
44722b15cb3dSCy Schubert 	void *addrp;
44732b15cb3dSCy Schubert 	int err;
44742b15cb3dSCy Schubert 	int user_canceled;
44752b15cb3dSCy Schubert 
44762b15cb3dSCy Schubert 	EVUTIL_ASSERT(req->type == DNS_IPv4_A || req->type == DNS_IPv6_AAAA);
44772b15cb3dSCy Schubert 	if (req->type == DNS_IPv4_A) {
44782b15cb3dSCy Schubert 		data = EVUTIL_UPCAST(req, struct evdns_getaddrinfo_request, ipv4_request);
44792b15cb3dSCy Schubert 		other_req = &data->ipv6_request;
44802b15cb3dSCy Schubert 	} else {
44812b15cb3dSCy Schubert 		data = EVUTIL_UPCAST(req, struct evdns_getaddrinfo_request, ipv6_request);
44822b15cb3dSCy Schubert 		other_req = &data->ipv4_request;
44832b15cb3dSCy Schubert 	}
44842b15cb3dSCy Schubert 
4485*a466cc55SCy Schubert 	/** Called from evdns_base_free() with @fail_requests == 1 */
4486*a466cc55SCy Schubert 	if (result != DNS_ERR_SHUTDOWN) {
44872b15cb3dSCy Schubert 		EVDNS_LOCK(data->evdns_base);
44882b15cb3dSCy Schubert 		if (evdns_result_is_answer(result)) {
44892b15cb3dSCy Schubert 			if (req->type == DNS_IPv4_A)
44902b15cb3dSCy Schubert 				++data->evdns_base->getaddrinfo_ipv4_answered;
44912b15cb3dSCy Schubert 			else
44922b15cb3dSCy Schubert 				++data->evdns_base->getaddrinfo_ipv6_answered;
44932b15cb3dSCy Schubert 		}
44942b15cb3dSCy Schubert 		user_canceled = data->user_canceled;
44952b15cb3dSCy Schubert 		if (other_req->r == NULL)
44962b15cb3dSCy Schubert 			data->request_done = 1;
44972b15cb3dSCy Schubert 		EVDNS_UNLOCK(data->evdns_base);
4498*a466cc55SCy Schubert 	} else {
4499*a466cc55SCy Schubert 		data->evdns_base = NULL;
4500*a466cc55SCy Schubert 		user_canceled = data->user_canceled;
4501*a466cc55SCy Schubert 	}
45022b15cb3dSCy Schubert 
45032b15cb3dSCy Schubert 	req->r = NULL;
45042b15cb3dSCy Schubert 
45052b15cb3dSCy Schubert 	if (result == DNS_ERR_CANCEL && ! user_canceled) {
45062b15cb3dSCy Schubert 		/* Internal cancel request from timeout or internal error.
45072b15cb3dSCy Schubert 		 * we already answered the user. */
45082b15cb3dSCy Schubert 		if (other_req->r == NULL)
45092b15cb3dSCy Schubert 			free_getaddrinfo_request(data);
45102b15cb3dSCy Schubert 		return;
45112b15cb3dSCy Schubert 	}
45122b15cb3dSCy Schubert 
45132b15cb3dSCy Schubert 	if (data->user_cb == NULL) {
45142b15cb3dSCy Schubert 		/* We already answered.  XXXX This shouldn't be needed; see
45152b15cb3dSCy Schubert 		 * comments in evdns_getaddrinfo_timeout_cb */
45162b15cb3dSCy Schubert 		free_getaddrinfo_request(data);
45172b15cb3dSCy Schubert 		return;
45182b15cb3dSCy Schubert 	}
45192b15cb3dSCy Schubert 
45202b15cb3dSCy Schubert 	if (result == DNS_ERR_NONE) {
45212b15cb3dSCy Schubert 		if (count == 0)
45222b15cb3dSCy Schubert 			err = EVUTIL_EAI_NODATA;
45232b15cb3dSCy Schubert 		else
45242b15cb3dSCy Schubert 			err = 0;
45252b15cb3dSCy Schubert 	} else {
45262b15cb3dSCy Schubert 		err = evdns_err_to_getaddrinfo_err(result);
45272b15cb3dSCy Schubert 	}
45282b15cb3dSCy Schubert 
45292b15cb3dSCy Schubert 	if (err) {
45302b15cb3dSCy Schubert 		/* Looks like we got an error. */
45312b15cb3dSCy Schubert 		if (other_req->r) {
45322b15cb3dSCy Schubert 			/* The other request is still working; maybe it will
45332b15cb3dSCy Schubert 			 * succeed. */
45342b15cb3dSCy Schubert 			/* XXXX handle failure from set_timeout */
4535*a466cc55SCy Schubert 			if (result != DNS_ERR_SHUTDOWN) {
45362b15cb3dSCy Schubert 				evdns_getaddrinfo_set_timeout(data->evdns_base, data);
4537*a466cc55SCy Schubert 			}
45382b15cb3dSCy Schubert 			data->pending_error = err;
45392b15cb3dSCy Schubert 			return;
45402b15cb3dSCy Schubert 		}
45412b15cb3dSCy Schubert 
45422b15cb3dSCy Schubert 		if (user_canceled) {
45432b15cb3dSCy Schubert 			data->user_cb(EVUTIL_EAI_CANCEL, NULL, data->user_data);
45442b15cb3dSCy Schubert 		} else if (data->pending_result) {
45452b15cb3dSCy Schubert 			/* If we have an answer waiting, and we weren't
45462b15cb3dSCy Schubert 			 * canceled, ignore this error. */
45472b15cb3dSCy Schubert 			add_cname_to_reply(data, data->pending_result);
45482b15cb3dSCy Schubert 			data->user_cb(0, data->pending_result, data->user_data);
45492b15cb3dSCy Schubert 			data->pending_result = NULL;
45502b15cb3dSCy Schubert 		} else {
45512b15cb3dSCy Schubert 			if (data->pending_error)
45522b15cb3dSCy Schubert 				err = getaddrinfo_merge_err(err,
45532b15cb3dSCy Schubert 				    data->pending_error);
45542b15cb3dSCy Schubert 			data->user_cb(err, NULL, data->user_data);
45552b15cb3dSCy Schubert 		}
45562b15cb3dSCy Schubert 		free_getaddrinfo_request(data);
45572b15cb3dSCy Schubert 		return;
45582b15cb3dSCy Schubert 	} else if (user_canceled) {
45592b15cb3dSCy Schubert 		if (other_req->r) {
45602b15cb3dSCy Schubert 			/* The other request is still working; let it hit this
45612b15cb3dSCy Schubert 			 * callback with EVUTIL_EAI_CANCEL callback and report
45622b15cb3dSCy Schubert 			 * the failure. */
45632b15cb3dSCy Schubert 			return;
45642b15cb3dSCy Schubert 		}
45652b15cb3dSCy Schubert 		data->user_cb(EVUTIL_EAI_CANCEL, NULL, data->user_data);
45662b15cb3dSCy Schubert 		free_getaddrinfo_request(data);
45672b15cb3dSCy Schubert 		return;
45682b15cb3dSCy Schubert 	}
45692b15cb3dSCy Schubert 
45702b15cb3dSCy Schubert 	/* Looks like we got some answers. We should turn them into addrinfos
45712b15cb3dSCy Schubert 	 * and then either queue those or return them all. */
45722b15cb3dSCy Schubert 	EVUTIL_ASSERT(type == DNS_IPv4_A || type == DNS_IPv6_AAAA);
45732b15cb3dSCy Schubert 
45742b15cb3dSCy Schubert 	if (type == DNS_IPv4_A) {
45752b15cb3dSCy Schubert 		memset(&sin, 0, sizeof(sin));
45762b15cb3dSCy Schubert 		sin.sin_family = AF_INET;
45772b15cb3dSCy Schubert 		sin.sin_port = htons(data->port);
45782b15cb3dSCy Schubert 
45792b15cb3dSCy Schubert 		sa = (struct sockaddr *)&sin;
45802b15cb3dSCy Schubert 		socklen = sizeof(sin);
45812b15cb3dSCy Schubert 		addrlen = 4;
45822b15cb3dSCy Schubert 		addrp = &sin.sin_addr.s_addr;
45832b15cb3dSCy Schubert 	} else {
45842b15cb3dSCy Schubert 		memset(&sin6, 0, sizeof(sin6));
45852b15cb3dSCy Schubert 		sin6.sin6_family = AF_INET6;
45862b15cb3dSCy Schubert 		sin6.sin6_port = htons(data->port);
45872b15cb3dSCy Schubert 
45882b15cb3dSCy Schubert 		sa = (struct sockaddr *)&sin6;
45892b15cb3dSCy Schubert 		socklen = sizeof(sin6);
45902b15cb3dSCy Schubert 		addrlen = 16;
45912b15cb3dSCy Schubert 		addrp = &sin6.sin6_addr.s6_addr;
45922b15cb3dSCy Schubert 	}
45932b15cb3dSCy Schubert 
45942b15cb3dSCy Schubert 	res = NULL;
45952b15cb3dSCy Schubert 	for (i=0; i < count; ++i) {
45962b15cb3dSCy Schubert 		struct evutil_addrinfo *ai;
45972b15cb3dSCy Schubert 		memcpy(addrp, ((char*)addresses)+i*addrlen, addrlen);
45982b15cb3dSCy Schubert 		ai = evutil_new_addrinfo_(sa, socklen, &data->hints);
45992b15cb3dSCy Schubert 		if (!ai) {
46002b15cb3dSCy Schubert 			if (other_req->r) {
46012b15cb3dSCy Schubert 				evdns_cancel_request(NULL, other_req->r);
46022b15cb3dSCy Schubert 			}
46032b15cb3dSCy Schubert 			data->user_cb(EVUTIL_EAI_MEMORY, NULL, data->user_data);
46042b15cb3dSCy Schubert 			if (res)
46052b15cb3dSCy Schubert 				evutil_freeaddrinfo(res);
46062b15cb3dSCy Schubert 
46072b15cb3dSCy Schubert 			if (other_req->r == NULL)
46082b15cb3dSCy Schubert 				free_getaddrinfo_request(data);
46092b15cb3dSCy Schubert 			return;
46102b15cb3dSCy Schubert 		}
46112b15cb3dSCy Schubert 		res = evutil_addrinfo_append_(res, ai);
46122b15cb3dSCy Schubert 	}
46132b15cb3dSCy Schubert 
46142b15cb3dSCy Schubert 	if (other_req->r) {
46152b15cb3dSCy Schubert 		/* The other request is still in progress; wait for it */
46162b15cb3dSCy Schubert 		/* XXXX handle failure from set_timeout */
46172b15cb3dSCy Schubert 		evdns_getaddrinfo_set_timeout(data->evdns_base, data);
46182b15cb3dSCy Schubert 		data->pending_result = res;
46192b15cb3dSCy Schubert 		return;
46202b15cb3dSCy Schubert 	} else {
46212b15cb3dSCy Schubert 		/* The other request is done or never started; append its
46222b15cb3dSCy Schubert 		 * results (if any) and return them. */
46232b15cb3dSCy Schubert 		if (data->pending_result) {
46242b15cb3dSCy Schubert 			if (req->type == DNS_IPv4_A)
46252b15cb3dSCy Schubert 				res = evutil_addrinfo_append_(res,
46262b15cb3dSCy Schubert 				    data->pending_result);
46272b15cb3dSCy Schubert 			else
46282b15cb3dSCy Schubert 				res = evutil_addrinfo_append_(
46292b15cb3dSCy Schubert 				    data->pending_result, res);
46302b15cb3dSCy Schubert 			data->pending_result = NULL;
46312b15cb3dSCy Schubert 		}
46322b15cb3dSCy Schubert 
46332b15cb3dSCy Schubert 		/* Call the user callback. */
46342b15cb3dSCy Schubert 		add_cname_to_reply(data, res);
46352b15cb3dSCy Schubert 		data->user_cb(0, res, data->user_data);
46362b15cb3dSCy Schubert 
46372b15cb3dSCy Schubert 		/* Free data. */
46382b15cb3dSCy Schubert 		free_getaddrinfo_request(data);
46392b15cb3dSCy Schubert 	}
46402b15cb3dSCy Schubert }
46412b15cb3dSCy Schubert 
46422b15cb3dSCy Schubert static struct hosts_entry *
find_hosts_entry(struct evdns_base * base,const char * hostname,struct hosts_entry * find_after)46432b15cb3dSCy Schubert find_hosts_entry(struct evdns_base *base, const char *hostname,
46442b15cb3dSCy Schubert     struct hosts_entry *find_after)
46452b15cb3dSCy Schubert {
46462b15cb3dSCy Schubert 	struct hosts_entry *e;
46472b15cb3dSCy Schubert 
46482b15cb3dSCy Schubert 	if (find_after)
46492b15cb3dSCy Schubert 		e = TAILQ_NEXT(find_after, next);
46502b15cb3dSCy Schubert 	else
46512b15cb3dSCy Schubert 		e = TAILQ_FIRST(&base->hostsdb);
46522b15cb3dSCy Schubert 
46532b15cb3dSCy Schubert 	for (; e; e = TAILQ_NEXT(e, next)) {
46542b15cb3dSCy Schubert 		if (!evutil_ascii_strcasecmp(e->hostname, hostname))
46552b15cb3dSCy Schubert 			return e;
46562b15cb3dSCy Schubert 	}
46572b15cb3dSCy Schubert 	return NULL;
46582b15cb3dSCy Schubert }
46592b15cb3dSCy Schubert 
46602b15cb3dSCy Schubert static int
evdns_getaddrinfo_fromhosts(struct evdns_base * base,const char * nodename,struct evutil_addrinfo * hints,ev_uint16_t port,struct evutil_addrinfo ** res)46612b15cb3dSCy Schubert evdns_getaddrinfo_fromhosts(struct evdns_base *base,
46622b15cb3dSCy Schubert     const char *nodename, struct evutil_addrinfo *hints, ev_uint16_t port,
46632b15cb3dSCy Schubert     struct evutil_addrinfo **res)
46642b15cb3dSCy Schubert {
46652b15cb3dSCy Schubert 	int n_found = 0;
46662b15cb3dSCy Schubert 	struct hosts_entry *e;
46672b15cb3dSCy Schubert 	struct evutil_addrinfo *ai=NULL;
46682b15cb3dSCy Schubert 	int f = hints->ai_family;
46692b15cb3dSCy Schubert 
46702b15cb3dSCy Schubert 	EVDNS_LOCK(base);
46712b15cb3dSCy Schubert 	for (e = find_hosts_entry(base, nodename, NULL); e;
46722b15cb3dSCy Schubert 	    e = find_hosts_entry(base, nodename, e)) {
46732b15cb3dSCy Schubert 		struct evutil_addrinfo *ai_new;
46742b15cb3dSCy Schubert 		++n_found;
46752b15cb3dSCy Schubert 		if ((e->addr.sa.sa_family == AF_INET && f == PF_INET6) ||
46762b15cb3dSCy Schubert 		    (e->addr.sa.sa_family == AF_INET6 && f == PF_INET))
46772b15cb3dSCy Schubert 			continue;
46782b15cb3dSCy Schubert 		ai_new = evutil_new_addrinfo_(&e->addr.sa, e->addrlen, hints);
46792b15cb3dSCy Schubert 		if (!ai_new) {
46802b15cb3dSCy Schubert 			n_found = 0;
46812b15cb3dSCy Schubert 			goto out;
46822b15cb3dSCy Schubert 		}
46832b15cb3dSCy Schubert 		sockaddr_setport(ai_new->ai_addr, port);
46842b15cb3dSCy Schubert 		ai = evutil_addrinfo_append_(ai, ai_new);
46852b15cb3dSCy Schubert 	}
46862b15cb3dSCy Schubert 	EVDNS_UNLOCK(base);
46872b15cb3dSCy Schubert out:
46882b15cb3dSCy Schubert 	if (n_found) {
46892b15cb3dSCy Schubert 		/* Note that we return an empty answer if we found entries for
46902b15cb3dSCy Schubert 		 * this hostname but none were of the right address type. */
46912b15cb3dSCy Schubert 		*res = ai;
46922b15cb3dSCy Schubert 		return 0;
46932b15cb3dSCy Schubert 	} else {
46942b15cb3dSCy Schubert 		if (ai)
46952b15cb3dSCy Schubert 			evutil_freeaddrinfo(ai);
46962b15cb3dSCy Schubert 		return -1;
46972b15cb3dSCy Schubert 	}
46982b15cb3dSCy Schubert }
46992b15cb3dSCy Schubert 
47002b15cb3dSCy Schubert struct evdns_getaddrinfo_request *
evdns_getaddrinfo(struct evdns_base * dns_base,const char * nodename,const char * servname,const struct evutil_addrinfo * hints_in,evdns_getaddrinfo_cb cb,void * arg)47012b15cb3dSCy Schubert evdns_getaddrinfo(struct evdns_base *dns_base,
47022b15cb3dSCy Schubert     const char *nodename, const char *servname,
47032b15cb3dSCy Schubert     const struct evutil_addrinfo *hints_in,
47042b15cb3dSCy Schubert     evdns_getaddrinfo_cb cb, void *arg)
47052b15cb3dSCy Schubert {
47062b15cb3dSCy Schubert 	struct evdns_getaddrinfo_request *data;
47072b15cb3dSCy Schubert 	struct evutil_addrinfo hints;
47082b15cb3dSCy Schubert 	struct evutil_addrinfo *res = NULL;
47092b15cb3dSCy Schubert 	int err;
47102b15cb3dSCy Schubert 	int port = 0;
47112b15cb3dSCy Schubert 	int want_cname = 0;
4712*a466cc55SCy Schubert 	int started = 0;
47132b15cb3dSCy Schubert 
47142b15cb3dSCy Schubert 	if (!dns_base) {
47152b15cb3dSCy Schubert 		dns_base = current_base;
47162b15cb3dSCy Schubert 		if (!dns_base) {
47172b15cb3dSCy Schubert 			log(EVDNS_LOG_WARN,
47182b15cb3dSCy Schubert 			    "Call to getaddrinfo_async with no "
47192b15cb3dSCy Schubert 			    "evdns_base configured.");
47202b15cb3dSCy Schubert 			cb(EVUTIL_EAI_FAIL, NULL, arg); /* ??? better error? */
47212b15cb3dSCy Schubert 			return NULL;
47222b15cb3dSCy Schubert 		}
47232b15cb3dSCy Schubert 	}
47242b15cb3dSCy Schubert 
47252b15cb3dSCy Schubert 	/* If we _must_ answer this immediately, do so. */
47262b15cb3dSCy Schubert 	if ((hints_in && (hints_in->ai_flags & EVUTIL_AI_NUMERICHOST))) {
47272b15cb3dSCy Schubert 		res = NULL;
47282b15cb3dSCy Schubert 		err = evutil_getaddrinfo(nodename, servname, hints_in, &res);
47292b15cb3dSCy Schubert 		cb(err, res, arg);
47302b15cb3dSCy Schubert 		return NULL;
47312b15cb3dSCy Schubert 	}
47322b15cb3dSCy Schubert 
47332b15cb3dSCy Schubert 	if (hints_in) {
47342b15cb3dSCy Schubert 		memcpy(&hints, hints_in, sizeof(hints));
47352b15cb3dSCy Schubert 	} else {
47362b15cb3dSCy Schubert 		memset(&hints, 0, sizeof(hints));
47372b15cb3dSCy Schubert 		hints.ai_family = PF_UNSPEC;
47382b15cb3dSCy Schubert 	}
47392b15cb3dSCy Schubert 
47402b15cb3dSCy Schubert 	evutil_adjust_hints_for_addrconfig_(&hints);
47412b15cb3dSCy Schubert 
47422b15cb3dSCy Schubert 	/* Now try to see if we _can_ answer immediately. */
47432b15cb3dSCy Schubert 	/* (It would be nice to do this by calling getaddrinfo directly, with
47442b15cb3dSCy Schubert 	 * AI_NUMERICHOST, on plaforms that have it, but we can't: there isn't
47452b15cb3dSCy Schubert 	 * a reliable way to distinguish the "that wasn't a numeric host!" case
47462b15cb3dSCy Schubert 	 * from any other EAI_NONAME cases.) */
47472b15cb3dSCy Schubert 	err = evutil_getaddrinfo_common_(nodename, servname, &hints, &res, &port);
47482b15cb3dSCy Schubert 	if (err != EVUTIL_EAI_NEED_RESOLVE) {
47492b15cb3dSCy Schubert 		cb(err, res, arg);
47502b15cb3dSCy Schubert 		return NULL;
47512b15cb3dSCy Schubert 	}
47522b15cb3dSCy Schubert 
47532b15cb3dSCy Schubert 	/* If there is an entry in the hosts file, we should give it now. */
47542b15cb3dSCy Schubert 	if (!evdns_getaddrinfo_fromhosts(dns_base, nodename, &hints, port, &res)) {
47552b15cb3dSCy Schubert 		cb(0, res, arg);
47562b15cb3dSCy Schubert 		return NULL;
47572b15cb3dSCy Schubert 	}
47582b15cb3dSCy Schubert 
47592b15cb3dSCy Schubert 	/* Okay, things are serious now. We're going to need to actually
47602b15cb3dSCy Schubert 	 * launch a request.
47612b15cb3dSCy Schubert 	 */
47622b15cb3dSCy Schubert 	data = mm_calloc(1,sizeof(struct evdns_getaddrinfo_request));
47632b15cb3dSCy Schubert 	if (!data) {
47642b15cb3dSCy Schubert 		cb(EVUTIL_EAI_MEMORY, NULL, arg);
47652b15cb3dSCy Schubert 		return NULL;
47662b15cb3dSCy Schubert 	}
47672b15cb3dSCy Schubert 
47682b15cb3dSCy Schubert 	memcpy(&data->hints, &hints, sizeof(data->hints));
47692b15cb3dSCy Schubert 	data->port = (ev_uint16_t)port;
47702b15cb3dSCy Schubert 	data->ipv4_request.type = DNS_IPv4_A;
47712b15cb3dSCy Schubert 	data->ipv6_request.type = DNS_IPv6_AAAA;
47722b15cb3dSCy Schubert 	data->user_cb = cb;
47732b15cb3dSCy Schubert 	data->user_data = arg;
47742b15cb3dSCy Schubert 	data->evdns_base = dns_base;
47752b15cb3dSCy Schubert 
47762b15cb3dSCy Schubert 	want_cname = (hints.ai_flags & EVUTIL_AI_CANONNAME);
47772b15cb3dSCy Schubert 
47782b15cb3dSCy Schubert 	/* If we are asked for a PF_UNSPEC address, we launch two requests in
47792b15cb3dSCy Schubert 	 * parallel: one for an A address and one for an AAAA address.  We
47802b15cb3dSCy Schubert 	 * can't send just one request, since many servers only answer one
47812b15cb3dSCy Schubert 	 * question per DNS request.
47822b15cb3dSCy Schubert 	 *
47832b15cb3dSCy Schubert 	 * Once we have the answer to one request, we allow for a short
47842b15cb3dSCy Schubert 	 * timeout before we report it, to see if the other one arrives.  If
47852b15cb3dSCy Schubert 	 * they both show up in time, then we report both the answers.
47862b15cb3dSCy Schubert 	 *
47872b15cb3dSCy Schubert 	 * If too many addresses of one type time out or fail, we should stop
47882b15cb3dSCy Schubert 	 * launching those requests. (XXX we don't do that yet.)
47892b15cb3dSCy Schubert 	 */
47902b15cb3dSCy Schubert 
4791*a466cc55SCy Schubert 	EVDNS_LOCK(dns_base);
4792*a466cc55SCy Schubert 
47932b15cb3dSCy Schubert 	if (hints.ai_family != PF_INET6) {
47942b15cb3dSCy Schubert 		log(EVDNS_LOG_DEBUG, "Sending request for %s on ipv4 as %p",
47952b15cb3dSCy Schubert 		    nodename, &data->ipv4_request);
47962b15cb3dSCy Schubert 
47972b15cb3dSCy Schubert 		data->ipv4_request.r = evdns_base_resolve_ipv4(dns_base,
47982b15cb3dSCy Schubert 		    nodename, 0, evdns_getaddrinfo_gotresolve,
47992b15cb3dSCy Schubert 		    &data->ipv4_request);
4800a25439b6SCy Schubert 		if (want_cname && data->ipv4_request.r)
48012b15cb3dSCy Schubert 			data->ipv4_request.r->current_req->put_cname_in_ptr =
48022b15cb3dSCy Schubert 			    &data->cname_result;
48032b15cb3dSCy Schubert 	}
48042b15cb3dSCy Schubert 	if (hints.ai_family != PF_INET) {
48052b15cb3dSCy Schubert 		log(EVDNS_LOG_DEBUG, "Sending request for %s on ipv6 as %p",
48062b15cb3dSCy Schubert 		    nodename, &data->ipv6_request);
48072b15cb3dSCy Schubert 
48082b15cb3dSCy Schubert 		data->ipv6_request.r = evdns_base_resolve_ipv6(dns_base,
48092b15cb3dSCy Schubert 		    nodename, 0, evdns_getaddrinfo_gotresolve,
48102b15cb3dSCy Schubert 		    &data->ipv6_request);
4811a25439b6SCy Schubert 		if (want_cname && data->ipv6_request.r)
48122b15cb3dSCy Schubert 			data->ipv6_request.r->current_req->put_cname_in_ptr =
48132b15cb3dSCy Schubert 			    &data->cname_result;
48142b15cb3dSCy Schubert 	}
48152b15cb3dSCy Schubert 
48162b15cb3dSCy Schubert 	evtimer_assign(&data->timeout, dns_base->event_base,
48172b15cb3dSCy Schubert 	    evdns_getaddrinfo_timeout_cb, data);
48182b15cb3dSCy Schubert 
4819*a466cc55SCy Schubert 	started = (data->ipv4_request.r || data->ipv6_request.r);
4820*a466cc55SCy Schubert 
4821*a466cc55SCy Schubert 	EVDNS_UNLOCK(dns_base);
4822*a466cc55SCy Schubert 
4823*a466cc55SCy Schubert 	if (started) {
48242b15cb3dSCy Schubert 		return data;
48252b15cb3dSCy Schubert 	} else {
48262b15cb3dSCy Schubert 		mm_free(data);
48272b15cb3dSCy Schubert 		cb(EVUTIL_EAI_FAIL, NULL, arg);
48282b15cb3dSCy Schubert 		return NULL;
48292b15cb3dSCy Schubert 	}
48302b15cb3dSCy Schubert }
48312b15cb3dSCy Schubert 
48322b15cb3dSCy Schubert void
evdns_getaddrinfo_cancel(struct evdns_getaddrinfo_request * data)48332b15cb3dSCy Schubert evdns_getaddrinfo_cancel(struct evdns_getaddrinfo_request *data)
48342b15cb3dSCy Schubert {
48352b15cb3dSCy Schubert 	EVDNS_LOCK(data->evdns_base);
48362b15cb3dSCy Schubert 	if (data->request_done) {
48372b15cb3dSCy Schubert 		EVDNS_UNLOCK(data->evdns_base);
48382b15cb3dSCy Schubert 		return;
48392b15cb3dSCy Schubert 	}
48402b15cb3dSCy Schubert 	event_del(&data->timeout);
48412b15cb3dSCy Schubert 	data->user_canceled = 1;
48422b15cb3dSCy Schubert 	if (data->ipv4_request.r)
48432b15cb3dSCy Schubert 		evdns_cancel_request(data->evdns_base, data->ipv4_request.r);
48442b15cb3dSCy Schubert 	if (data->ipv6_request.r)
48452b15cb3dSCy Schubert 		evdns_cancel_request(data->evdns_base, data->ipv6_request.r);
48462b15cb3dSCy Schubert 	EVDNS_UNLOCK(data->evdns_base);
48472b15cb3dSCy Schubert }
4848