ipc/chromium/src/third_party/libevent/evdns.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/ipc/chromium/src/third_party/libevent/evdns.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,4655 @@
     1.4 +/* Copyright 2006-2007 Niels Provos
     1.5 + * Copyright 2007-2012 Nick Mathewson and Niels Provos
     1.6 + *
     1.7 + * Redistribution and use in source and binary forms, with or without
     1.8 + * modification, are permitted provided that the following conditions
     1.9 + * are met:
    1.10 + * 1. Redistributions of source code must retain the above copyright
    1.11 + *    notice, this list of conditions and the following disclaimer.
    1.12 + * 2. Redistributions in binary form must reproduce the above copyright
    1.13 + *    notice, this list of conditions and the following disclaimer in the
    1.14 + *    documentation and/or other materials provided with the distribution.
    1.15 + * 3. The name of the author may not be used to endorse or promote products
    1.16 + *    derived from this software without specific prior written permission.
    1.17 + *
    1.18 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
    1.19 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    1.20 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
    1.21 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
    1.22 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
    1.23 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    1.24 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    1.25 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    1.26 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    1.27 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    1.28 + */
    1.29 +
    1.30 +/* Based on software by Adam Langly. Adam's original message:
    1.31 + *
    1.32 + * Async DNS Library
    1.33 + * Adam Langley <agl@imperialviolet.org>
    1.34 + * http://www.imperialviolet.org/eventdns.html
    1.35 + * Public Domain code
    1.36 + *
    1.37 + * This software is Public Domain. To view a copy of the public domain dedication,
    1.38 + * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
    1.39 + * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
    1.40 + *
    1.41 + * I ask and expect, but do not require, that all derivative works contain an
    1.42 + * attribution similar to:
    1.43 + *	Parts developed by Adam Langley <agl@imperialviolet.org>
    1.44 + *
    1.45 + * You may wish to replace the word "Parts" with something else depending on
    1.46 + * the amount of original code.
    1.47 + *
    1.48 + * (Derivative works does not include programs which link against, run or include
    1.49 + * the source verbatim in their source distributions)
    1.50 + *
    1.51 + * Version: 0.1b
    1.52 + */
    1.53 +
    1.54 +#include <sys/types.h>
    1.55 +#include "event2/event-config.h"
    1.56 +
    1.57 +#ifndef _FORTIFY_SOURCE
    1.58 +#define _FORTIFY_SOURCE 3
    1.59 +#endif
    1.60 +
    1.61 +#include <string.h>
    1.62 +#include <fcntl.h>
    1.63 +#ifdef _EVENT_HAVE_SYS_TIME_H
    1.64 +#include <sys/time.h>
    1.65 +#endif
    1.66 +#ifdef _EVENT_HAVE_STDINT_H
    1.67 +#include <stdint.h>
    1.68 +#endif
    1.69 +#include <stdlib.h>
    1.70 +#include <string.h>
    1.71 +#include <errno.h>
    1.72 +#ifdef _EVENT_HAVE_UNISTD_H
    1.73 +#include <unistd.h>
    1.74 +#endif
    1.75 +#include <limits.h>
    1.76 +#include <sys/stat.h>
    1.77 +#include <stdio.h>
    1.78 +#include <stdarg.h>
    1.79 +#ifdef WIN32
    1.80 +#include <winsock2.h>
    1.81 +#include <ws2tcpip.h>
    1.82 +#ifndef _WIN32_IE
    1.83 +#define _WIN32_IE 0x400
    1.84 +#endif
    1.85 +#include <shlobj.h>
    1.86 +#endif
    1.87 +
    1.88 +#include "event2/dns.h"
    1.89 +#include "event2/dns_struct.h"
    1.90 +#include "event2/dns_compat.h"
    1.91 +#include "event2/util.h"
    1.92 +#include "event2/event.h"
    1.93 +#include "event2/event_struct.h"
    1.94 +#include "event2/thread.h"
    1.95 +
    1.96 +#include "event2/bufferevent.h"
    1.97 +#include "event2/bufferevent_struct.h"
    1.98 +#include "bufferevent-internal.h"
    1.99 +
   1.100 +#include "defer-internal.h"
   1.101 +#include "log-internal.h"
   1.102 +#include "mm-internal.h"
   1.103 +#include "strlcpy-internal.h"
   1.104 +#include "ipv6-internal.h"
   1.105 +#include "util-internal.h"
   1.106 +#include "evthread-internal.h"
   1.107 +#ifdef WIN32
   1.108 +#include <ctype.h>
   1.109 +#include <winsock2.h>
   1.110 +#include <windows.h>
   1.111 +#include <iphlpapi.h>
   1.112 +#include <io.h>
   1.113 +#else
   1.114 +#include <sys/socket.h>
   1.115 +#include <netinet/in.h>
   1.116 +#include <arpa/inet.h>
   1.117 +#endif
   1.118 +
   1.119 +#ifdef _EVENT_HAVE_NETINET_IN6_H
   1.120 +#include <netinet/in6.h>
   1.121 +#endif
   1.122 +
   1.123 +#define EVDNS_LOG_DEBUG 0
   1.124 +#define EVDNS_LOG_WARN 1
   1.125 +#define EVDNS_LOG_MSG 2
   1.126 +
   1.127 +#ifndef HOST_NAME_MAX
   1.128 +#define HOST_NAME_MAX 255
   1.129 +#endif
   1.130 +
   1.131 +#include <stdio.h>
   1.132 +
   1.133 +#undef MIN
   1.134 +#define MIN(a,b) ((a)<(b)?(a):(b))
   1.135 +
   1.136 +#define ASSERT_VALID_REQUEST(req) \
   1.137 +	EVUTIL_ASSERT((req)->handle && (req)->handle->current_req == (req))
   1.138 +
   1.139 +#define u64 ev_uint64_t
   1.140 +#define u32 ev_uint32_t
   1.141 +#define u16 ev_uint16_t
   1.142 +#define u8  ev_uint8_t
   1.143 +
   1.144 +/* maximum number of addresses from a single packet */
   1.145 +/* that we bother recording */
   1.146 +#define MAX_V4_ADDRS 32
   1.147 +#define MAX_V6_ADDRS 32
   1.148 +
   1.149 +
   1.150 +#define TYPE_A	       EVDNS_TYPE_A
   1.151 +#define TYPE_CNAME     5
   1.152 +#define TYPE_PTR       EVDNS_TYPE_PTR
   1.153 +#define TYPE_SOA       EVDNS_TYPE_SOA
   1.154 +#define TYPE_AAAA      EVDNS_TYPE_AAAA
   1.155 +
   1.156 +#define CLASS_INET     EVDNS_CLASS_INET
   1.157 +
   1.158 +/* Persistent handle.  We keep this separate from 'struct request' since we
   1.159 + * need some object to last for as long as an evdns_request is outstanding so
   1.160 + * that it can be canceled, whereas a search request can lead to multiple
   1.161 + * 'struct request' instances being created over its lifetime. */
   1.162 +struct evdns_request {
   1.163 +	struct request *current_req;
   1.164 +	struct evdns_base *base;
   1.165 +
   1.166 +	int pending_cb; /* Waiting for its callback to be invoked; not
   1.167 +			 * owned by event base any more. */
   1.168 +
   1.169 +	/* elements used by the searching code */
   1.170 +	int search_index;
   1.171 +	struct search_state *search_state;
   1.172 +	char *search_origname;	/* needs to be free()ed */
   1.173 +	int search_flags;
   1.174 +};
   1.175 +
   1.176 +struct request {
   1.177 +	u8 *request;  /* the dns packet data */
   1.178 +	u8 request_type; /* TYPE_PTR or TYPE_A or TYPE_AAAA */
   1.179 +	unsigned int request_len;
   1.180 +	int reissue_count;
   1.181 +	int tx_count;  /* the number of times that this packet has been sent */
   1.182 +	void *user_pointer;  /* the pointer given to us for this request */
   1.183 +	evdns_callback_type user_callback;
   1.184 +	struct nameserver *ns;	/* the server which we last sent it */
   1.185 +
   1.186 +	/* these objects are kept in a circular list */
   1.187 +	/* XXX We could turn this into a CIRCLEQ. */
   1.188 +	struct request *next, *prev;
   1.189 +
   1.190 +	struct event timeout_event;
   1.191 +
   1.192 +	u16 trans_id;  /* the transaction id */
   1.193 +	unsigned request_appended :1;	/* true if the request pointer is data which follows this struct */
   1.194 +	unsigned transmit_me :1;  /* needs to be transmitted */
   1.195 +
   1.196 +	/* XXXX This is a horrible hack. */
   1.197 +	char **put_cname_in_ptr; /* store the cname here if we get one. */
   1.198 +
   1.199 +	struct evdns_base *base;
   1.200 +
   1.201 +	struct evdns_request *handle;
   1.202 +};
   1.203 +
   1.204 +struct reply {
   1.205 +	unsigned int type;
   1.206 +	unsigned int have_answer : 1;
   1.207 +	union {
   1.208 +		struct {
   1.209 +			u32 addrcount;
   1.210 +			u32 addresses[MAX_V4_ADDRS];
   1.211 +		} a;
   1.212 +		struct {
   1.213 +			u32 addrcount;
   1.214 +			struct in6_addr addresses[MAX_V6_ADDRS];
   1.215 +		} aaaa;
   1.216 +		struct {
   1.217 +			char name[HOST_NAME_MAX];
   1.218 +		} ptr;
   1.219 +	} data;
   1.220 +};
   1.221 +
   1.222 +struct nameserver {
   1.223 +	evutil_socket_t socket;	 /* a connected UDP socket */
   1.224 +	struct sockaddr_storage address;
   1.225 +	ev_socklen_t addrlen;
   1.226 +	int failed_times;  /* number of times which we have given this server a chance */
   1.227 +	int timedout;  /* number of times in a row a request has timed out */
   1.228 +	struct event event;
   1.229 +	/* these objects are kept in a circular list */
   1.230 +	struct nameserver *next, *prev;
   1.231 +	struct event timeout_event;  /* used to keep the timeout for */
   1.232 +				     /* when we next probe this server. */
   1.233 +				     /* Valid if state == 0 */
   1.234 +	/* Outstanding probe request for this nameserver, if any */
   1.235 +	struct evdns_request *probe_request;
   1.236 +	char state;  /* zero if we think that this server is down */
   1.237 +	char choked;  /* true if we have an EAGAIN from this server's socket */
   1.238 +	char write_waiting;  /* true if we are waiting for EV_WRITE events */
   1.239 +	struct evdns_base *base;
   1.240 +};
   1.241 +
   1.242 +
   1.243 +/* Represents a local port where we're listening for DNS requests. Right now, */
   1.244 +/* only UDP is supported. */
   1.245 +struct evdns_server_port {
   1.246 +	evutil_socket_t socket; /* socket we use to read queries and write replies. */
   1.247 +	int refcnt; /* reference count. */
   1.248 +	char choked; /* Are we currently blocked from writing? */
   1.249 +	char closing; /* Are we trying to close this port, pending writes? */
   1.250 +	evdns_request_callback_fn_type user_callback; /* Fn to handle requests */
   1.251 +	void *user_data; /* Opaque pointer passed to user_callback */
   1.252 +	struct event event; /* Read/write event */
   1.253 +	/* circular list of replies that we want to write. */
   1.254 +	struct server_request *pending_replies;
   1.255 +	struct event_base *event_base;
   1.256 +
   1.257 +#ifndef _EVENT_DISABLE_THREAD_SUPPORT
   1.258 +	void *lock;
   1.259 +#endif
   1.260 +};
   1.261 +
   1.262 +/* Represents part of a reply being built.	(That is, a single RR.) */
   1.263 +struct server_reply_item {
   1.264 +	struct server_reply_item *next; /* next item in sequence. */
   1.265 +	char *name; /* name part of the RR */
   1.266 +	u16 type; /* The RR type */
   1.267 +	u16 class; /* The RR class (usually CLASS_INET) */
   1.268 +	u32 ttl; /* The RR TTL */
   1.269 +	char is_name; /* True iff data is a label */
   1.270 +	u16 datalen; /* Length of data; -1 if data is a label */
   1.271 +	void *data; /* The contents of the RR */
   1.272 +};
   1.273 +
   1.274 +/* Represents a request that we've received as a DNS server, and holds */
   1.275 +/* the components of the reply as we're constructing it. */
   1.276 +struct server_request {
   1.277 +	/* Pointers to the next and previous entries on the list of replies */
   1.278 +	/* that we're waiting to write.	 Only set if we have tried to respond */
   1.279 +	/* and gotten EAGAIN. */
   1.280 +	struct server_request *next_pending;
   1.281 +	struct server_request *prev_pending;
   1.282 +
   1.283 +	u16 trans_id; /* Transaction id. */
   1.284 +	struct evdns_server_port *port; /* Which port received this request on? */
   1.285 +	struct sockaddr_storage addr; /* Where to send the response */
   1.286 +	ev_socklen_t addrlen; /* length of addr */
   1.287 +
   1.288 +	int n_answer; /* how many answer RRs have been set? */
   1.289 +	int n_authority; /* how many authority RRs have been set? */
   1.290 +	int n_additional; /* how many additional RRs have been set? */
   1.291 +
   1.292 +	struct server_reply_item *answer; /* linked list of answer RRs */
   1.293 +	struct server_reply_item *authority; /* linked list of authority RRs */
   1.294 +	struct server_reply_item *additional; /* linked list of additional RRs */
   1.295 +
   1.296 +	/* Constructed response.  Only set once we're ready to send a reply. */
   1.297 +	/* Once this is set, the RR fields are cleared, and no more should be set. */
   1.298 +	char *response;
   1.299 +	size_t response_len;
   1.300 +
   1.301 +	/* Caller-visible fields: flags, questions. */
   1.302 +	struct evdns_server_request base;
   1.303 +};
   1.304 +
   1.305 +struct evdns_base {
   1.306 +	/* An array of n_req_heads circular lists for inflight requests.
   1.307 +	 * Each inflight request req is in req_heads[req->trans_id % n_req_heads].
   1.308 +	 */
   1.309 +	struct request **req_heads;
   1.310 +	/* A circular list of requests that we're waiting to send, but haven't
   1.311 +	 * sent yet because there are too many requests inflight */
   1.312 +	struct request *req_waiting_head;
   1.313 +	/* A circular list of nameservers. */
   1.314 +	struct nameserver *server_head;
   1.315 +	int n_req_heads;
   1.316 +
   1.317 +	struct event_base *event_base;
   1.318 +
   1.319 +	/* The number of good nameservers that we have */
   1.320 +	int global_good_nameservers;
   1.321 +
   1.322 +	/* inflight requests are contained in the req_head list */
   1.323 +	/* and are actually going out across the network */
   1.324 +	int global_requests_inflight;
   1.325 +	/* requests which aren't inflight are in the waiting list */
   1.326 +	/* and are counted here */
   1.327 +	int global_requests_waiting;
   1.328 +
   1.329 +	int global_max_requests_inflight;
   1.330 +
   1.331 +	struct timeval global_timeout;	/* 5 seconds by default */
   1.332 +	int global_max_reissues;  /* a reissue occurs when we get some errors from the server */
   1.333 +	int global_max_retransmits;  /* number of times we'll retransmit a request which timed out */
   1.334 +	/* number of timeouts in a row before we consider this server to be down */
   1.335 +	int global_max_nameserver_timeout;
   1.336 +	/* true iff we will use the 0x20 hack to prevent poisoning attacks. */
   1.337 +	int global_randomize_case;
   1.338 +
   1.339 +	/* The first time that a nameserver fails, how long do we wait before
   1.340 +	 * probing to see if it has returned?  */
   1.341 +	struct timeval global_nameserver_probe_initial_timeout;
   1.342 +
   1.343 +	/** Port to bind to for outgoing DNS packets. */
   1.344 +	struct sockaddr_storage global_outgoing_address;
   1.345 +	/** ev_socklen_t for global_outgoing_address. 0 if it isn't set. */
   1.346 +	ev_socklen_t global_outgoing_addrlen;
   1.347 +
   1.348 +	struct timeval global_getaddrinfo_allow_skew;
   1.349 +
   1.350 +	int getaddrinfo_ipv4_timeouts;
   1.351 +	int getaddrinfo_ipv6_timeouts;
   1.352 +	int getaddrinfo_ipv4_answered;
   1.353 +	int getaddrinfo_ipv6_answered;
   1.354 +
   1.355 +	struct search_state *global_search_state;
   1.356 +
   1.357 +	TAILQ_HEAD(hosts_list, hosts_entry) hostsdb;
   1.358 +
   1.359 +#ifndef _EVENT_DISABLE_THREAD_SUPPORT
   1.360 +	void *lock;
   1.361 +#endif
   1.362 +};
   1.363 +
   1.364 +struct hosts_entry {
   1.365 +	TAILQ_ENTRY(hosts_entry) next;
   1.366 +	union {
   1.367 +		struct sockaddr sa;
   1.368 +		struct sockaddr_in sin;
   1.369 +		struct sockaddr_in6 sin6;
   1.370 +	} addr;
   1.371 +	int addrlen;
   1.372 +	char hostname[1];
   1.373 +};
   1.374 +
   1.375 +static struct evdns_base *current_base = NULL;
   1.376 +
   1.377 +struct evdns_base *
   1.378 +evdns_get_global_base(void)
   1.379 +{
   1.380 +	return current_base;
   1.381 +}
   1.382 +
   1.383 +/* Given a pointer to an evdns_server_request, get the corresponding */
   1.384 +/* server_request. */
   1.385 +#define TO_SERVER_REQUEST(base_ptr)					\
   1.386 +	((struct server_request*)					\
   1.387 +	  (((char*)(base_ptr) - evutil_offsetof(struct server_request, base))))
   1.388 +
   1.389 +#define REQ_HEAD(base, id) ((base)->req_heads[id % (base)->n_req_heads])
   1.390 +
   1.391 +static struct nameserver *nameserver_pick(struct evdns_base *base);
   1.392 +static void evdns_request_insert(struct request *req, struct request **head);
   1.393 +static void evdns_request_remove(struct request *req, struct request **head);
   1.394 +static void nameserver_ready_callback(evutil_socket_t fd, short events, void *arg);
   1.395 +static int evdns_transmit(struct evdns_base *base);
   1.396 +static int evdns_request_transmit(struct request *req);
   1.397 +static void nameserver_send_probe(struct nameserver *const ns);
   1.398 +static void search_request_finished(struct evdns_request *const);
   1.399 +static int search_try_next(struct evdns_request *const req);
   1.400 +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);
   1.401 +static void evdns_requests_pump_waiting_queue(struct evdns_base *base);
   1.402 +static u16 transaction_id_pick(struct evdns_base *base);
   1.403 +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);
   1.404 +static void request_submit(struct request *const req);
   1.405 +
   1.406 +static int server_request_free(struct server_request *req);
   1.407 +static void server_request_free_answers(struct server_request *req);
   1.408 +static void server_port_free(struct evdns_server_port *port);
   1.409 +static void server_port_ready_callback(evutil_socket_t fd, short events, void *arg);
   1.410 +static int evdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags, const char *const filename);
   1.411 +static int evdns_base_set_option_impl(struct evdns_base *base,
   1.412 +    const char *option, const char *val, int flags);
   1.413 +static void evdns_base_free_and_unlock(struct evdns_base *base, int fail_requests);
   1.414 +
   1.415 +static int strtoint(const char *const str);
   1.416 +
   1.417 +#ifdef _EVENT_DISABLE_THREAD_SUPPORT
   1.418 +#define EVDNS_LOCK(base)  _EVUTIL_NIL_STMT
   1.419 +#define EVDNS_UNLOCK(base) _EVUTIL_NIL_STMT
   1.420 +#define ASSERT_LOCKED(base) _EVUTIL_NIL_STMT
   1.421 +#else
   1.422 +#define EVDNS_LOCK(base)			\
   1.423 +	EVLOCK_LOCK((base)->lock, 0)
   1.424 +#define EVDNS_UNLOCK(base)			\
   1.425 +	EVLOCK_UNLOCK((base)->lock, 0)
   1.426 +#define ASSERT_LOCKED(base)			\
   1.427 +	EVLOCK_ASSERT_LOCKED((base)->lock)
   1.428 +#endif
   1.429 +
   1.430 +static void
   1.431 +default_evdns_log_fn(int warning, const char *buf)
   1.432 +{
   1.433 +	if (warning == EVDNS_LOG_WARN)
   1.434 +		event_warnx("[evdns] %s", buf);
   1.435 +	else if (warning == EVDNS_LOG_MSG)
   1.436 +		event_msgx("[evdns] %s", buf);
   1.437 +	else
   1.438 +		event_debug(("[evdns] %s", buf));
   1.439 +}
   1.440 +
   1.441 +static evdns_debug_log_fn_type evdns_log_fn = NULL;
   1.442 +
   1.443 +void
   1.444 +evdns_set_log_fn(evdns_debug_log_fn_type fn)
   1.445 +{
   1.446 +	evdns_log_fn = fn;
   1.447 +}
   1.448 +
   1.449 +#ifdef __GNUC__
   1.450 +#define EVDNS_LOG_CHECK	 __attribute__ ((format(printf, 2, 3)))
   1.451 +#else
   1.452 +#define EVDNS_LOG_CHECK
   1.453 +#endif
   1.454 +
   1.455 +static void _evdns_log(int warn, const char *fmt, ...) EVDNS_LOG_CHECK;
   1.456 +static void
   1.457 +_evdns_log(int warn, const char *fmt, ...)
   1.458 +{
   1.459 +	va_list args;
   1.460 +	char buf[512];
   1.461 +	if (!evdns_log_fn)
   1.462 +		return;
   1.463 +	va_start(args,fmt);
   1.464 +	evutil_vsnprintf(buf, sizeof(buf), fmt, args);
   1.465 +	va_end(args);
   1.466 +	if (evdns_log_fn) {
   1.467 +		if (warn == EVDNS_LOG_MSG)
   1.468 +			warn = EVDNS_LOG_WARN;
   1.469 +		evdns_log_fn(warn, buf);
   1.470 +	} else {
   1.471 +		default_evdns_log_fn(warn, buf);
   1.472 +	}
   1.473 +
   1.474 +}
   1.475 +
   1.476 +#define log _evdns_log
   1.477 +
   1.478 +/* This walks the list of inflight requests to find the */
   1.479 +/* one with a matching transaction id. Returns NULL on */
   1.480 +/* failure */
   1.481 +static struct request *
   1.482 +request_find_from_trans_id(struct evdns_base *base, u16 trans_id) {
   1.483 +	struct request *req = REQ_HEAD(base, trans_id);
   1.484 +	struct request *const started_at = req;
   1.485 +
   1.486 +	ASSERT_LOCKED(base);
   1.487 +
   1.488 +	if (req) {
   1.489 +		do {
   1.490 +			if (req->trans_id == trans_id) return req;
   1.491 +			req = req->next;
   1.492 +		} while (req != started_at);
   1.493 +	}
   1.494 +
   1.495 +	return NULL;
   1.496 +}
   1.497 +
   1.498 +/* a libevent callback function which is called when a nameserver */
   1.499 +/* has gone down and we want to test if it has came back to life yet */
   1.500 +static void
   1.501 +nameserver_prod_callback(evutil_socket_t fd, short events, void *arg) {
   1.502 +	struct nameserver *const ns = (struct nameserver *) arg;
   1.503 +	(void)fd;
   1.504 +	(void)events;
   1.505 +
   1.506 +	EVDNS_LOCK(ns->base);
   1.507 +	nameserver_send_probe(ns);
   1.508 +	EVDNS_UNLOCK(ns->base);
   1.509 +}
   1.510 +
   1.511 +/* a libevent callback which is called when a nameserver probe (to see if */
   1.512 +/* it has come back to life) times out. We increment the count of failed_times */
   1.513 +/* and wait longer to send the next probe packet. */
   1.514 +static void
   1.515 +nameserver_probe_failed(struct nameserver *const ns) {
   1.516 +	struct timeval timeout;
   1.517 +	int i;
   1.518 +
   1.519 +	ASSERT_LOCKED(ns->base);
   1.520 +	(void) evtimer_del(&ns->timeout_event);
   1.521 +	if (ns->state == 1) {
   1.522 +		/* This can happen if the nameserver acts in a way which makes us mark */
   1.523 +		/* it as bad and then starts sending good replies. */
   1.524 +		return;
   1.525 +	}
   1.526 +
   1.527 +#define MAX_PROBE_TIMEOUT 3600
   1.528 +#define TIMEOUT_BACKOFF_FACTOR 3
   1.529 +
   1.530 +	memcpy(&timeout, &ns->base->global_nameserver_probe_initial_timeout,
   1.531 +	    sizeof(struct timeval));
   1.532 +	for (i=ns->failed_times; i > 0 && timeout.tv_sec < MAX_PROBE_TIMEOUT; --i) {
   1.533 +		timeout.tv_sec *= TIMEOUT_BACKOFF_FACTOR;
   1.534 +		timeout.tv_usec *= TIMEOUT_BACKOFF_FACTOR;
   1.535 +		if (timeout.tv_usec > 1000000) {
   1.536 +			timeout.tv_sec += timeout.tv_usec / 1000000;
   1.537 +			timeout.tv_usec %= 1000000;
   1.538 +		}
   1.539 +	}
   1.540 +	if (timeout.tv_sec > MAX_PROBE_TIMEOUT) {
   1.541 +		timeout.tv_sec = MAX_PROBE_TIMEOUT;
   1.542 +		timeout.tv_usec = 0;
   1.543 +	}
   1.544 +
   1.545 +	ns->failed_times++;
   1.546 +
   1.547 +	if (evtimer_add(&ns->timeout_event, &timeout) < 0) {
   1.548 +		char addrbuf[128];
   1.549 +		log(EVDNS_LOG_WARN,
   1.550 +		    "Error from libevent when adding timer event for %s",
   1.551 +		    evutil_format_sockaddr_port(
   1.552 +			    (struct sockaddr *)&ns->address,
   1.553 +			    addrbuf, sizeof(addrbuf)));
   1.554 +	}
   1.555 +}
   1.556 +
   1.557 +/* called when a nameserver has been deemed to have failed. For example, too */
   1.558 +/* many packets have timed out etc */
   1.559 +static void
   1.560 +nameserver_failed(struct nameserver *const ns, const char *msg) {
   1.561 +	struct request *req, *started_at;
   1.562 +	struct evdns_base *base = ns->base;
   1.563 +	int i;
   1.564 +	char addrbuf[128];
   1.565 +
   1.566 +	ASSERT_LOCKED(base);
   1.567 +	/* if this nameserver has already been marked as failed */
   1.568 +	/* then don't do anything */
   1.569 +	if (!ns->state) return;
   1.570 +
   1.571 +	log(EVDNS_LOG_MSG, "Nameserver %s has failed: %s",
   1.572 +	    evutil_format_sockaddr_port(
   1.573 +		    (struct sockaddr *)&ns->address,
   1.574 +		    addrbuf, sizeof(addrbuf)),
   1.575 +	    msg);
   1.576 +
   1.577 +	base->global_good_nameservers--;
   1.578 +	EVUTIL_ASSERT(base->global_good_nameservers >= 0);
   1.579 +	if (base->global_good_nameservers == 0) {
   1.580 +		log(EVDNS_LOG_MSG, "All nameservers have failed");
   1.581 +	}
   1.582 +
   1.583 +	ns->state = 0;
   1.584 +	ns->failed_times = 1;
   1.585 +
   1.586 +	if (evtimer_add(&ns->timeout_event,
   1.587 +		&base->global_nameserver_probe_initial_timeout) < 0) {
   1.588 +		log(EVDNS_LOG_WARN,
   1.589 +		    "Error from libevent when adding timer event for %s",
   1.590 +		    evutil_format_sockaddr_port(
   1.591 +			    (struct sockaddr *)&ns->address,
   1.592 +			    addrbuf, sizeof(addrbuf)));
   1.593 +		/* ???? Do more? */
   1.594 +	}
   1.595 +
   1.596 +	/* walk the list of inflight requests to see if any can be reassigned to */
   1.597 +	/* a different server. Requests in the waiting queue don't have a */
   1.598 +	/* nameserver assigned yet */
   1.599 +
   1.600 +	/* if we don't have *any* good nameservers then there's no point */
   1.601 +	/* trying to reassign requests to one */
   1.602 +	if (!base->global_good_nameservers) return;
   1.603 +
   1.604 +	for (i = 0; i < base->n_req_heads; ++i) {
   1.605 +		req = started_at = base->req_heads[i];
   1.606 +		if (req) {
   1.607 +			do {
   1.608 +				if (req->tx_count == 0 && req->ns == ns) {
   1.609 +					/* still waiting to go out, can be moved */
   1.610 +					/* to another server */
   1.611 +					req->ns = nameserver_pick(base);
   1.612 +				}
   1.613 +				req = req->next;
   1.614 +			} while (req != started_at);
   1.615 +		}
   1.616 +	}
   1.617 +}
   1.618 +
   1.619 +static void
   1.620 +nameserver_up(struct nameserver *const ns)
   1.621 +{
   1.622 +	char addrbuf[128];
   1.623 +	ASSERT_LOCKED(ns->base);
   1.624 +	if (ns->state) return;
   1.625 +	log(EVDNS_LOG_MSG, "Nameserver %s is back up",
   1.626 +	    evutil_format_sockaddr_port(
   1.627 +		    (struct sockaddr *)&ns->address,
   1.628 +		    addrbuf, sizeof(addrbuf)));
   1.629 +	evtimer_del(&ns->timeout_event);
   1.630 +	if (ns->probe_request) {
   1.631 +		evdns_cancel_request(ns->base, ns->probe_request);
   1.632 +		ns->probe_request = NULL;
   1.633 +	}
   1.634 +	ns->state = 1;
   1.635 +	ns->failed_times = 0;
   1.636 +	ns->timedout = 0;
   1.637 +	ns->base->global_good_nameservers++;
   1.638 +}
   1.639 +
   1.640 +static void
   1.641 +request_trans_id_set(struct request *const req, const u16 trans_id) {
   1.642 +	req->trans_id = trans_id;
   1.643 +	*((u16 *) req->request) = htons(trans_id);
   1.644 +}
   1.645 +
   1.646 +/* Called to remove a request from a list and dealloc it. */
   1.647 +/* head is a pointer to the head of the list it should be */
   1.648 +/* removed from or NULL if the request isn't in a list. */
   1.649 +/* when free_handle is one, free the handle as well. */
   1.650 +static void
   1.651 +request_finished(struct request *const req, struct request **head, int free_handle) {
   1.652 +	struct evdns_base *base = req->base;
   1.653 +	int was_inflight = (head != &base->req_waiting_head);
   1.654 +	EVDNS_LOCK(base);
   1.655 +	ASSERT_VALID_REQUEST(req);
   1.656 +
   1.657 +	if (head)
   1.658 +		evdns_request_remove(req, head);
   1.659 +
   1.660 +	log(EVDNS_LOG_DEBUG, "Removing timeout for request %p", req);
   1.661 +	if (was_inflight) {
   1.662 +		evtimer_del(&req->timeout_event);
   1.663 +		base->global_requests_inflight--;
   1.664 +	} else {
   1.665 +		base->global_requests_waiting--;
   1.666 +	}
   1.667 +	/* it was initialized during request_new / evtimer_assign */
   1.668 +	event_debug_unassign(&req->timeout_event);
   1.669 +
   1.670 +	if (!req->request_appended) {
   1.671 +		/* need to free the request data on it's own */
   1.672 +		mm_free(req->request);
   1.673 +	} else {
   1.674 +		/* the request data is appended onto the header */
   1.675 +		/* so everything gets free()ed when we: */
   1.676 +	}
   1.677 +
   1.678 +	if (req->handle) {
   1.679 +		EVUTIL_ASSERT(req->handle->current_req == req);
   1.680 +
   1.681 +		if (free_handle) {
   1.682 +			search_request_finished(req->handle);
   1.683 +			req->handle->current_req = NULL;
   1.684 +			if (! req->handle->pending_cb) {
   1.685 +				/* If we're planning to run the callback,
   1.686 +				 * don't free the handle until later. */
   1.687 +				mm_free(req->handle);
   1.688 +			}
   1.689 +			req->handle = NULL; /* If we have a bug, let's crash
   1.690 +					     * early */
   1.691 +		} else {
   1.692 +			req->handle->current_req = NULL;
   1.693 +		}
   1.694 +	}
   1.695 +
   1.696 +	mm_free(req);
   1.697 +
   1.698 +	evdns_requests_pump_waiting_queue(base);
   1.699 +	EVDNS_UNLOCK(base);
   1.700 +}
   1.701 +
   1.702 +/* This is called when a server returns a funny error code. */
   1.703 +/* We try the request again with another server. */
   1.704 +/* */
   1.705 +/* return: */
   1.706 +/*   0 ok */
   1.707 +/*   1 failed/reissue is pointless */
   1.708 +static int
   1.709 +request_reissue(struct request *req) {
   1.710 +	const struct nameserver *const last_ns = req->ns;
   1.711 +	ASSERT_LOCKED(req->base);
   1.712 +	ASSERT_VALID_REQUEST(req);
   1.713 +	/* the last nameserver should have been marked as failing */
   1.714 +	/* by the caller of this function, therefore pick will try */
   1.715 +	/* not to return it */
   1.716 +	req->ns = nameserver_pick(req->base);
   1.717 +	if (req->ns == last_ns) {
   1.718 +		/* ... but pick did return it */
   1.719 +		/* not a lot of point in trying again with the */
   1.720 +		/* same server */
   1.721 +		return 1;
   1.722 +	}
   1.723 +
   1.724 +	req->reissue_count++;
   1.725 +	req->tx_count = 0;
   1.726 +	req->transmit_me = 1;
   1.727 +
   1.728 +	return 0;
   1.729 +}
   1.730 +
   1.731 +/* this function looks for space on the inflight queue and promotes */
   1.732 +/* requests from the waiting queue if it can. */
   1.733 +static void
   1.734 +evdns_requests_pump_waiting_queue(struct evdns_base *base) {
   1.735 +	ASSERT_LOCKED(base);
   1.736 +	while (base->global_requests_inflight < base->global_max_requests_inflight &&
   1.737 +		   base->global_requests_waiting) {
   1.738 +		struct request *req;
   1.739 +		/* move a request from the waiting queue to the inflight queue */
   1.740 +		EVUTIL_ASSERT(base->req_waiting_head);
   1.741 +		req = base->req_waiting_head;
   1.742 +		evdns_request_remove(req, &base->req_waiting_head);
   1.743 +
   1.744 +		base->global_requests_waiting--;
   1.745 +		base->global_requests_inflight++;
   1.746 +
   1.747 +		req->ns = nameserver_pick(base);
   1.748 +		request_trans_id_set(req, transaction_id_pick(base));
   1.749 +
   1.750 +		evdns_request_insert(req, &REQ_HEAD(base, req->trans_id));
   1.751 +		evdns_request_transmit(req);
   1.752 +		evdns_transmit(base);
   1.753 +	}
   1.754 +}
   1.755 +
   1.756 +/* TODO(nickm) document */
   1.757 +struct deferred_reply_callback {
   1.758 +	struct deferred_cb deferred;
   1.759 +	struct evdns_request *handle;
   1.760 +	u8 request_type;
   1.761 +	u8 have_reply;
   1.762 +	u32 ttl;
   1.763 +	u32 err;
   1.764 +	evdns_callback_type user_callback;
   1.765 +	struct reply reply;
   1.766 +};
   1.767 +
   1.768 +static void
   1.769 +reply_run_callback(struct deferred_cb *d, void *user_pointer)
   1.770 +{
   1.771 +	struct deferred_reply_callback *cb =
   1.772 +	    EVUTIL_UPCAST(d, struct deferred_reply_callback, deferred);
   1.773 +
   1.774 +	switch (cb->request_type) {
   1.775 +	case TYPE_A:
   1.776 +		if (cb->have_reply)
   1.777 +			cb->user_callback(DNS_ERR_NONE, DNS_IPv4_A,
   1.778 +			    cb->reply.data.a.addrcount, cb->ttl,
   1.779 +			    cb->reply.data.a.addresses,
   1.780 +			    user_pointer);
   1.781 +		else
   1.782 +			cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer);
   1.783 +		break;
   1.784 +	case TYPE_PTR:
   1.785 +		if (cb->have_reply) {
   1.786 +			char *name = cb->reply.data.ptr.name;
   1.787 +			cb->user_callback(DNS_ERR_NONE, DNS_PTR, 1, cb->ttl,
   1.788 +			    &name, user_pointer);
   1.789 +		} else {
   1.790 +			cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer);
   1.791 +		}
   1.792 +		break;
   1.793 +	case TYPE_AAAA:
   1.794 +		if (cb->have_reply)
   1.795 +			cb->user_callback(DNS_ERR_NONE, DNS_IPv6_AAAA,
   1.796 +			    cb->reply.data.aaaa.addrcount, cb->ttl,
   1.797 +			    cb->reply.data.aaaa.addresses,
   1.798 +			    user_pointer);
   1.799 +		else
   1.800 +			cb->user_callback(cb->err, 0, 0, cb->ttl, NULL, user_pointer);
   1.801 +		break;
   1.802 +	default:
   1.803 +		EVUTIL_ASSERT(0);
   1.804 +	}
   1.805 +
   1.806 +	if (cb->handle && cb->handle->pending_cb) {
   1.807 +		mm_free(cb->handle);
   1.808 +	}
   1.809 +
   1.810 +	mm_free(cb);
   1.811 +}
   1.812 +
   1.813 +static void
   1.814 +reply_schedule_callback(struct request *const req, u32 ttl, u32 err, struct reply *reply)
   1.815 +{
   1.816 +	struct deferred_reply_callback *d = mm_calloc(1, sizeof(*d));
   1.817 +
   1.818 +	if (!d) {
   1.819 +		event_warn("%s: Couldn't allocate space for deferred callback.",
   1.820 +		    __func__);
   1.821 +		return;
   1.822 +	}
   1.823 +
   1.824 +	ASSERT_LOCKED(req->base);
   1.825 +
   1.826 +	d->request_type = req->request_type;
   1.827 +	d->user_callback = req->user_callback;
   1.828 +	d->ttl = ttl;
   1.829 +	d->err = err;
   1.830 +	if (reply) {
   1.831 +		d->have_reply = 1;
   1.832 +		memcpy(&d->reply, reply, sizeof(struct reply));
   1.833 +	}
   1.834 +
   1.835 +	if (req->handle) {
   1.836 +		req->handle->pending_cb = 1;
   1.837 +		d->handle = req->handle;
   1.838 +	}
   1.839 +
   1.840 +	event_deferred_cb_init(&d->deferred, reply_run_callback,
   1.841 +	    req->user_pointer);
   1.842 +	event_deferred_cb_schedule(
   1.843 +		event_base_get_deferred_cb_queue(req->base->event_base),
   1.844 +		&d->deferred);
   1.845 +}
   1.846 +
   1.847 +/* this processes a parsed reply packet */
   1.848 +static void
   1.849 +reply_handle(struct request *const req, u16 flags, u32 ttl, struct reply *reply) {
   1.850 +	int error;
   1.851 +	char addrbuf[128];
   1.852 +	static const int error_codes[] = {
   1.853 +		DNS_ERR_FORMAT, DNS_ERR_SERVERFAILED, DNS_ERR_NOTEXIST,
   1.854 +		DNS_ERR_NOTIMPL, DNS_ERR_REFUSED
   1.855 +	};
   1.856 +
   1.857 +	ASSERT_LOCKED(req->base);
   1.858 +	ASSERT_VALID_REQUEST(req);
   1.859 +
   1.860 +	if (flags & 0x020f || !reply || !reply->have_answer) {
   1.861 +		/* there was an error */
   1.862 +		if (flags & 0x0200) {
   1.863 +			error = DNS_ERR_TRUNCATED;
   1.864 +		} else if (flags & 0x000f) {
   1.865 +			u16 error_code = (flags & 0x000f) - 1;
   1.866 +			if (error_code > 4) {
   1.867 +				error = DNS_ERR_UNKNOWN;
   1.868 +			} else {
   1.869 +				error = error_codes[error_code];
   1.870 +			}
   1.871 +		} else if (reply && !reply->have_answer) {
   1.872 +			error = DNS_ERR_NODATA;
   1.873 +		} else {
   1.874 +			error = DNS_ERR_UNKNOWN;
   1.875 +		}
   1.876 +
   1.877 +		switch (error) {
   1.878 +		case DNS_ERR_NOTIMPL:
   1.879 +		case DNS_ERR_REFUSED:
   1.880 +			/* we regard these errors as marking a bad nameserver */
   1.881 +			if (req->reissue_count < req->base->global_max_reissues) {
   1.882 +				char msg[64];
   1.883 +				evutil_snprintf(msg, sizeof(msg), "Bad response %d (%s)",
   1.884 +					 error, evdns_err_to_string(error));
   1.885 +				nameserver_failed(req->ns, msg);
   1.886 +				if (!request_reissue(req)) return;
   1.887 +			}
   1.888 +			break;
   1.889 +		case DNS_ERR_SERVERFAILED:
   1.890 +			/* rcode 2 (servfailed) sometimes means "we
   1.891 +			 * are broken" and sometimes (with some binds)
   1.892 +			 * means "that request was very confusing."
   1.893 +			 * Treat this as a timeout, not a failure.
   1.894 +			 */
   1.895 +			log(EVDNS_LOG_DEBUG, "Got a SERVERFAILED from nameserver"
   1.896 +				"at %s; will allow the request to time out.",
   1.897 +			    evutil_format_sockaddr_port(
   1.898 +				    (struct sockaddr *)&req->ns->address,
   1.899 +				    addrbuf, sizeof(addrbuf)));
   1.900 +			break;
   1.901 +		default:
   1.902 +			/* we got a good reply from the nameserver: it is up. */
   1.903 +			if (req->handle == req->ns->probe_request) {
   1.904 +				/* Avoid double-free */
   1.905 +				req->ns->probe_request = NULL;
   1.906 +			}
   1.907 +
   1.908 +			nameserver_up(req->ns);
   1.909 +		}
   1.910 +
   1.911 +		if (req->handle->search_state &&
   1.912 +		    req->request_type != TYPE_PTR) {
   1.913 +			/* if we have a list of domains to search in,
   1.914 +			 * try the next one */
   1.915 +			if (!search_try_next(req->handle)) {
   1.916 +				/* a new request was issued so this
   1.917 +				 * request is finished and */
   1.918 +				/* the user callback will be made when
   1.919 +				 * that request (or a */
   1.920 +				/* child of it) finishes. */
   1.921 +				return;
   1.922 +			}
   1.923 +		}
   1.924 +
   1.925 +		/* all else failed. Pass the failure up */
   1.926 +		reply_schedule_callback(req, ttl, error, NULL);
   1.927 +		request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1);
   1.928 +	} else {
   1.929 +		/* all ok, tell the user */
   1.930 +		reply_schedule_callback(req, ttl, 0, reply);
   1.931 +		if (req->handle == req->ns->probe_request)
   1.932 +			req->ns->probe_request = NULL; /* Avoid double-free */
   1.933 +		nameserver_up(req->ns);
   1.934 +		request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1);
   1.935 +	}
   1.936 +}
   1.937 +
   1.938 +static int
   1.939 +name_parse(u8 *packet, int length, int *idx, char *name_out, int name_out_len) {
   1.940 +	int name_end = -1;
   1.941 +	int j = *idx;
   1.942 +	int ptr_count = 0;
   1.943 +#define GET32(x) do { if (j + 4 > length) goto err; memcpy(&_t32, packet + j, 4); j += 4; x = ntohl(_t32); } while (0)
   1.944 +#define GET16(x) do { if (j + 2 > length) goto err; memcpy(&_t, packet + j, 2); j += 2; x = ntohs(_t); } while (0)
   1.945 +#define GET8(x) do { if (j >= length) goto err; x = packet[j++]; } while (0)
   1.946 +
   1.947 +	char *cp = name_out;
   1.948 +	const char *const end = name_out + name_out_len;
   1.949 +
   1.950 +	/* Normally, names are a series of length prefixed strings terminated */
   1.951 +	/* with a length of 0 (the lengths are u8's < 63). */
   1.952 +	/* However, the length can start with a pair of 1 bits and that */
   1.953 +	/* means that the next 14 bits are a pointer within the current */
   1.954 +	/* packet. */
   1.955 +
   1.956 +	for (;;) {
   1.957 +		u8 label_len;
   1.958 +		if (j >= length) return -1;
   1.959 +		GET8(label_len);
   1.960 +		if (!label_len) break;
   1.961 +		if (label_len & 0xc0) {
   1.962 +			u8 ptr_low;
   1.963 +			GET8(ptr_low);
   1.964 +			if (name_end < 0) name_end = j;
   1.965 +			j = (((int)label_len & 0x3f) << 8) + ptr_low;
   1.966 +			/* Make sure that the target offset is in-bounds. */
   1.967 +			if (j < 0 || j >= length) return -1;
   1.968 +			/* If we've jumped more times than there are characters in the
   1.969 +			 * message, we must have a loop. */
   1.970 +			if (++ptr_count > length) return -1;
   1.971 +			continue;
   1.972 +		}
   1.973 +		if (label_len > 63) return -1;
   1.974 +		if (cp != name_out) {
   1.975 +			if (cp + 1 >= end) return -1;
   1.976 +			*cp++ = '.';
   1.977 +		}
   1.978 +		if (cp + label_len >= end) return -1;
   1.979 +		memcpy(cp, packet + j, label_len);
   1.980 +		cp += label_len;
   1.981 +		j += label_len;
   1.982 +	}
   1.983 +	if (cp >= end) return -1;
   1.984 +	*cp = '\0';
   1.985 +	if (name_end < 0)
   1.986 +		*idx = j;
   1.987 +	else
   1.988 +		*idx = name_end;
   1.989 +	return 0;
   1.990 + err:
   1.991 +	return -1;
   1.992 +}
   1.993 +
   1.994 +/* parses a raw request from a nameserver */
   1.995 +static int
   1.996 +reply_parse(struct evdns_base *base, u8 *packet, int length) {
   1.997 +	int j = 0, k = 0;  /* index into packet */
   1.998 +	u16 _t;	 /* used by the macros */
   1.999 +	u32 _t32;  /* used by the macros */
  1.1000 +	char tmp_name[256], cmp_name[256]; /* used by the macros */
  1.1001 +	int name_matches = 0;
  1.1002 +
  1.1003 +	u16 trans_id, questions, answers, authority, additional, datalength;
  1.1004 +	u16 flags = 0;
  1.1005 +	u32 ttl, ttl_r = 0xffffffff;
  1.1006 +	struct reply reply;
  1.1007 +	struct request *req = NULL;
  1.1008 +	unsigned int i;
  1.1009 +
  1.1010 +	ASSERT_LOCKED(base);
  1.1011 +
  1.1012 +	GET16(trans_id);
  1.1013 +	GET16(flags);
  1.1014 +	GET16(questions);
  1.1015 +	GET16(answers);
  1.1016 +	GET16(authority);
  1.1017 +	GET16(additional);
  1.1018 +	(void) authority; /* suppress "unused variable" warnings. */
  1.1019 +	(void) additional; /* suppress "unused variable" warnings. */
  1.1020 +
  1.1021 +	req = request_find_from_trans_id(base, trans_id);
  1.1022 +	if (!req) return -1;
  1.1023 +	EVUTIL_ASSERT(req->base == base);
  1.1024 +
  1.1025 +	memset(&reply, 0, sizeof(reply));
  1.1026 +
  1.1027 +	/* If it's not an answer, it doesn't correspond to any request. */
  1.1028 +	if (!(flags & 0x8000)) return -1;  /* must be an answer */
  1.1029 +	if ((flags & 0x020f) && (flags & 0x020f) != DNS_ERR_NOTEXIST) {
  1.1030 +		/* there was an error and it's not NXDOMAIN */
  1.1031 +		goto err;
  1.1032 +	}
  1.1033 +	/* if (!answers) return; */  /* must have an answer of some form */
  1.1034 +
  1.1035 +	/* This macro skips a name in the DNS reply. */
  1.1036 +#define SKIP_NAME						\
  1.1037 +	do { tmp_name[0] = '\0';				\
  1.1038 +		if (name_parse(packet, length, &j, tmp_name,	\
  1.1039 +			sizeof(tmp_name))<0)			\
  1.1040 +			goto err;				\
  1.1041 +	} while (0)
  1.1042 +#define TEST_NAME							\
  1.1043 +	do { tmp_name[0] = '\0';					\
  1.1044 +		cmp_name[0] = '\0';					\
  1.1045 +		k = j;							\
  1.1046 +		if (name_parse(packet, length, &j, tmp_name,		\
  1.1047 +			sizeof(tmp_name))<0)				\
  1.1048 +			goto err;					\
  1.1049 +		if (name_parse(req->request, req->request_len, &k,	\
  1.1050 +			cmp_name, sizeof(cmp_name))<0)			\
  1.1051 +			goto err;					\
  1.1052 +		if (base->global_randomize_case) {			\
  1.1053 +			if (strcmp(tmp_name, cmp_name) == 0)		\
  1.1054 +				name_matches = 1;			\
  1.1055 +		} else {						\
  1.1056 +			if (evutil_ascii_strcasecmp(tmp_name, cmp_name) == 0) \
  1.1057 +				name_matches = 1;			\
  1.1058 +		}							\
  1.1059 +	} while (0)
  1.1060 +
  1.1061 +	reply.type = req->request_type;
  1.1062 +
  1.1063 +	/* skip over each question in the reply */
  1.1064 +	for (i = 0; i < questions; ++i) {
  1.1065 +		/* the question looks like
  1.1066 +		 *   <label:name><u16:type><u16:class>
  1.1067 +		 */
  1.1068 +		TEST_NAME;
  1.1069 +		j += 4;
  1.1070 +		if (j > length) goto err;
  1.1071 +	}
  1.1072 +
  1.1073 +	if (!name_matches)
  1.1074 +		goto err;
  1.1075 +
  1.1076 +	/* now we have the answer section which looks like
  1.1077 +	 * <label:name><u16:type><u16:class><u32:ttl><u16:len><data...>
  1.1078 +	 */
  1.1079 +
  1.1080 +	for (i = 0; i < answers; ++i) {
  1.1081 +		u16 type, class;
  1.1082 +
  1.1083 +		SKIP_NAME;
  1.1084 +		GET16(type);
  1.1085 +		GET16(class);
  1.1086 +		GET32(ttl);
  1.1087 +		GET16(datalength);
  1.1088 +
  1.1089 +		if (type == TYPE_A && class == CLASS_INET) {
  1.1090 +			int addrcount, addrtocopy;
  1.1091 +			if (req->request_type != TYPE_A) {
  1.1092 +				j += datalength; continue;
  1.1093 +			}
  1.1094 +			if ((datalength & 3) != 0) /* not an even number of As. */
  1.1095 +			    goto err;
  1.1096 +			addrcount = datalength >> 2;
  1.1097 +			addrtocopy = MIN(MAX_V4_ADDRS - reply.data.a.addrcount, (unsigned)addrcount);
  1.1098 +
  1.1099 +			ttl_r = MIN(ttl_r, ttl);
  1.1100 +			/* we only bother with the first four addresses. */
  1.1101 +			if (j + 4*addrtocopy > length) goto err;
  1.1102 +			memcpy(&reply.data.a.addresses[reply.data.a.addrcount],
  1.1103 +				   packet + j, 4*addrtocopy);
  1.1104 +			j += 4*addrtocopy;
  1.1105 +			reply.data.a.addrcount += addrtocopy;
  1.1106 +			reply.have_answer = 1;
  1.1107 +			if (reply.data.a.addrcount == MAX_V4_ADDRS) break;
  1.1108 +		} else if (type == TYPE_PTR && class == CLASS_INET) {
  1.1109 +			if (req->request_type != TYPE_PTR) {
  1.1110 +				j += datalength; continue;
  1.1111 +			}
  1.1112 +			if (name_parse(packet, length, &j, reply.data.ptr.name,
  1.1113 +						   sizeof(reply.data.ptr.name))<0)
  1.1114 +				goto err;
  1.1115 +			ttl_r = MIN(ttl_r, ttl);
  1.1116 +			reply.have_answer = 1;
  1.1117 +			break;
  1.1118 +		} else if (type == TYPE_CNAME) {
  1.1119 +			char cname[HOST_NAME_MAX];
  1.1120 +			if (!req->put_cname_in_ptr || *req->put_cname_in_ptr) {
  1.1121 +				j += datalength; continue;
  1.1122 +			}
  1.1123 +			if (name_parse(packet, length, &j, cname,
  1.1124 +				sizeof(cname))<0)
  1.1125 +				goto err;
  1.1126 +			*req->put_cname_in_ptr = mm_strdup(cname);
  1.1127 +		} else if (type == TYPE_AAAA && class == CLASS_INET) {
  1.1128 +			int addrcount, addrtocopy;
  1.1129 +			if (req->request_type != TYPE_AAAA) {
  1.1130 +				j += datalength; continue;
  1.1131 +			}
  1.1132 +			if ((datalength & 15) != 0) /* not an even number of AAAAs. */
  1.1133 +				goto err;
  1.1134 +			addrcount = datalength >> 4;  /* each address is 16 bytes long */
  1.1135 +			addrtocopy = MIN(MAX_V6_ADDRS - reply.data.aaaa.addrcount, (unsigned)addrcount);
  1.1136 +			ttl_r = MIN(ttl_r, ttl);
  1.1137 +
  1.1138 +			/* we only bother with the first four addresses. */
  1.1139 +			if (j + 16*addrtocopy > length) goto err;
  1.1140 +			memcpy(&reply.data.aaaa.addresses[reply.data.aaaa.addrcount],
  1.1141 +				   packet + j, 16*addrtocopy);
  1.1142 +			reply.data.aaaa.addrcount += addrtocopy;
  1.1143 +			j += 16*addrtocopy;
  1.1144 +			reply.have_answer = 1;
  1.1145 +			if (reply.data.aaaa.addrcount == MAX_V6_ADDRS) break;
  1.1146 +		} else {
  1.1147 +			/* skip over any other type of resource */
  1.1148 +			j += datalength;
  1.1149 +		}
  1.1150 +	}
  1.1151 +
  1.1152 +	if (!reply.have_answer) {
  1.1153 +		for (i = 0; i < authority; ++i) {
  1.1154 +			u16 type, class;
  1.1155 +			SKIP_NAME;
  1.1156 +			GET16(type);
  1.1157 +			GET16(class);
  1.1158 +			GET32(ttl);
  1.1159 +			GET16(datalength);
  1.1160 +			if (type == TYPE_SOA && class == CLASS_INET) {
  1.1161 +				u32 serial, refresh, retry, expire, minimum;
  1.1162 +				SKIP_NAME;
  1.1163 +				SKIP_NAME;
  1.1164 +				GET32(serial);
  1.1165 +				GET32(refresh);
  1.1166 +				GET32(retry);
  1.1167 +				GET32(expire);
  1.1168 +				GET32(minimum);
  1.1169 +				(void)expire;
  1.1170 +				(void)retry;
  1.1171 +				(void)refresh;
  1.1172 +				(void)serial;
  1.1173 +				ttl_r = MIN(ttl_r, ttl);
  1.1174 +				ttl_r = MIN(ttl_r, minimum);
  1.1175 +			} else {
  1.1176 +				/* skip over any other type of resource */
  1.1177 +				j += datalength;
  1.1178 +			}
  1.1179 +		}
  1.1180 +	}
  1.1181 +
  1.1182 +	if (ttl_r == 0xffffffff)
  1.1183 +		ttl_r = 0;
  1.1184 +
  1.1185 +	reply_handle(req, flags, ttl_r, &reply);
  1.1186 +	return 0;
  1.1187 + err:
  1.1188 +	if (req)
  1.1189 +		reply_handle(req, flags, 0, NULL);
  1.1190 +	return -1;
  1.1191 +}
  1.1192 +
  1.1193 +/* Parse a raw request (packet,length) sent to a nameserver port (port) from */
  1.1194 +/* a DNS client (addr,addrlen), and if it's well-formed, call the corresponding */
  1.1195 +/* callback. */
  1.1196 +static int
  1.1197 +request_parse(u8 *packet, int length, struct evdns_server_port *port, struct sockaddr *addr, ev_socklen_t addrlen)
  1.1198 +{
  1.1199 +	int j = 0;	/* index into packet */
  1.1200 +	u16 _t;	 /* used by the macros */
  1.1201 +	char tmp_name[256]; /* used by the macros */
  1.1202 +
  1.1203 +	int i;
  1.1204 +	u16 trans_id, flags, questions, answers, authority, additional;
  1.1205 +	struct server_request *server_req = NULL;
  1.1206 +
  1.1207 +	ASSERT_LOCKED(port);
  1.1208 +
  1.1209 +	/* Get the header fields */
  1.1210 +	GET16(trans_id);
  1.1211 +	GET16(flags);
  1.1212 +	GET16(questions);
  1.1213 +	GET16(answers);
  1.1214 +	GET16(authority);
  1.1215 +	GET16(additional);
  1.1216 +	(void)answers;
  1.1217 +	(void)additional;
  1.1218 +	(void)authority;
  1.1219 +
  1.1220 +	if (flags & 0x8000) return -1; /* Must not be an answer. */
  1.1221 +	flags &= 0x0110; /* Only RD and CD get preserved. */
  1.1222 +
  1.1223 +	server_req = mm_malloc(sizeof(struct server_request));
  1.1224 +	if (server_req == NULL) return -1;
  1.1225 +	memset(server_req, 0, sizeof(struct server_request));
  1.1226 +
  1.1227 +	server_req->trans_id = trans_id;
  1.1228 +	memcpy(&server_req->addr, addr, addrlen);
  1.1229 +	server_req->addrlen = addrlen;
  1.1230 +
  1.1231 +	server_req->base.flags = flags;
  1.1232 +	server_req->base.nquestions = 0;
  1.1233 +	server_req->base.questions = mm_calloc(sizeof(struct evdns_server_question *), questions);
  1.1234 +	if (server_req->base.questions == NULL)
  1.1235 +		goto err;
  1.1236 +
  1.1237 +	for (i = 0; i < questions; ++i) {
  1.1238 +		u16 type, class;
  1.1239 +		struct evdns_server_question *q;
  1.1240 +		int namelen;
  1.1241 +		if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0)
  1.1242 +			goto err;
  1.1243 +		GET16(type);
  1.1244 +		GET16(class);
  1.1245 +		namelen = (int)strlen(tmp_name);
  1.1246 +		q = mm_malloc(sizeof(struct evdns_server_question) + namelen);
  1.1247 +		if (!q)
  1.1248 +			goto err;
  1.1249 +		q->type = type;
  1.1250 +		q->dns_question_class = class;
  1.1251 +		memcpy(q->name, tmp_name, namelen+1);
  1.1252 +		server_req->base.questions[server_req->base.nquestions++] = q;
  1.1253 +	}
  1.1254 +
  1.1255 +	/* Ignore answers, authority, and additional. */
  1.1256 +
  1.1257 +	server_req->port = port;
  1.1258 +	port->refcnt++;
  1.1259 +
  1.1260 +	/* Only standard queries are supported. */
  1.1261 +	if (flags & 0x7800) {
  1.1262 +		evdns_server_request_respond(&(server_req->base), DNS_ERR_NOTIMPL);
  1.1263 +		return -1;
  1.1264 +	}
  1.1265 +
  1.1266 +	port->user_callback(&(server_req->base), port->user_data);
  1.1267 +
  1.1268 +	return 0;
  1.1269 +err:
  1.1270 +	if (server_req) {
  1.1271 +		if (server_req->base.questions) {
  1.1272 +			for (i = 0; i < server_req->base.nquestions; ++i)
  1.1273 +				mm_free(server_req->base.questions[i]);
  1.1274 +			mm_free(server_req->base.questions);
  1.1275 +		}
  1.1276 +		mm_free(server_req);
  1.1277 +	}
  1.1278 +	return -1;
  1.1279 +
  1.1280 +#undef SKIP_NAME
  1.1281 +#undef GET32
  1.1282 +#undef GET16
  1.1283 +#undef GET8
  1.1284 +}
  1.1285 +
  1.1286 +
  1.1287 +void
  1.1288 +evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void))
  1.1289 +{
  1.1290 +}
  1.1291 +
  1.1292 +void
  1.1293 +evdns_set_random_bytes_fn(void (*fn)(char *, size_t))
  1.1294 +{
  1.1295 +}
  1.1296 +
  1.1297 +/* Try to choose a strong transaction id which isn't already in flight */
  1.1298 +static u16
  1.1299 +transaction_id_pick(struct evdns_base *base) {
  1.1300 +	ASSERT_LOCKED(base);
  1.1301 +	for (;;) {
  1.1302 +		u16 trans_id;
  1.1303 +		evutil_secure_rng_get_bytes(&trans_id, sizeof(trans_id));
  1.1304 +
  1.1305 +		if (trans_id == 0xffff) continue;
  1.1306 +		/* now check to see if that id is already inflight */
  1.1307 +		if (request_find_from_trans_id(base, trans_id) == NULL)
  1.1308 +			return trans_id;
  1.1309 +	}
  1.1310 +}
  1.1311 +
  1.1312 +/* choose a namesever to use. This function will try to ignore */
  1.1313 +/* nameservers which we think are down and load balance across the rest */
  1.1314 +/* by updating the server_head global each time. */
  1.1315 +static struct nameserver *
  1.1316 +nameserver_pick(struct evdns_base *base) {
  1.1317 +	struct nameserver *started_at = base->server_head, *picked;
  1.1318 +	ASSERT_LOCKED(base);
  1.1319 +	if (!base->server_head) return NULL;
  1.1320 +
  1.1321 +	/* if we don't have any good nameservers then there's no */
  1.1322 +	/* point in trying to find one. */
  1.1323 +	if (!base->global_good_nameservers) {
  1.1324 +		base->server_head = base->server_head->next;
  1.1325 +		return base->server_head;
  1.1326 +	}
  1.1327 +
  1.1328 +	/* remember that nameservers are in a circular list */
  1.1329 +	for (;;) {
  1.1330 +		if (base->server_head->state) {
  1.1331 +			/* we think this server is currently good */
  1.1332 +			picked = base->server_head;
  1.1333 +			base->server_head = base->server_head->next;
  1.1334 +			return picked;
  1.1335 +		}
  1.1336 +
  1.1337 +		base->server_head = base->server_head->next;
  1.1338 +		if (base->server_head == started_at) {
  1.1339 +			/* all the nameservers seem to be down */
  1.1340 +			/* so we just return this one and hope for the */
  1.1341 +			/* best */
  1.1342 +			EVUTIL_ASSERT(base->global_good_nameservers == 0);
  1.1343 +			picked = base->server_head;
  1.1344 +			base->server_head = base->server_head->next;
  1.1345 +			return picked;
  1.1346 +		}
  1.1347 +	}
  1.1348 +}
  1.1349 +
  1.1350 +/* this is called when a namesever socket is ready for reading */
  1.1351 +static void
  1.1352 +nameserver_read(struct nameserver *ns) {
  1.1353 +	struct sockaddr_storage ss;
  1.1354 +	ev_socklen_t addrlen = sizeof(ss);
  1.1355 +	u8 packet[1500];
  1.1356 +	char addrbuf[128];
  1.1357 +	ASSERT_LOCKED(ns->base);
  1.1358 +
  1.1359 +	for (;;) {
  1.1360 +		const int r = recvfrom(ns->socket, (void*)packet,
  1.1361 +		    sizeof(packet), 0,
  1.1362 +		    (struct sockaddr*)&ss, &addrlen);
  1.1363 +		if (r < 0) {
  1.1364 +			int err = evutil_socket_geterror(ns->socket);
  1.1365 +			if (EVUTIL_ERR_RW_RETRIABLE(err))
  1.1366 +				return;
  1.1367 +			nameserver_failed(ns,
  1.1368 +			    evutil_socket_error_to_string(err));
  1.1369 +			return;
  1.1370 +		}
  1.1371 +		if (evutil_sockaddr_cmp((struct sockaddr*)&ss,
  1.1372 +			(struct sockaddr*)&ns->address, 0)) {
  1.1373 +			log(EVDNS_LOG_WARN, "Address mismatch on received "
  1.1374 +			    "DNS packet.  Apparent source was %s",
  1.1375 +			    evutil_format_sockaddr_port(
  1.1376 +				    (struct sockaddr *)&ss,
  1.1377 +				    addrbuf, sizeof(addrbuf)));
  1.1378 +			return;
  1.1379 +		}
  1.1380 +
  1.1381 +		ns->timedout = 0;
  1.1382 +		reply_parse(ns->base, packet, r);
  1.1383 +	}
  1.1384 +}
  1.1385 +
  1.1386 +/* Read a packet from a DNS client on a server port s, parse it, and */
  1.1387 +/* act accordingly. */
  1.1388 +static void
  1.1389 +server_port_read(struct evdns_server_port *s) {
  1.1390 +	u8 packet[1500];
  1.1391 +	struct sockaddr_storage addr;
  1.1392 +	ev_socklen_t addrlen;
  1.1393 +	int r;
  1.1394 +	ASSERT_LOCKED(s);
  1.1395 +
  1.1396 +	for (;;) {
  1.1397 +		addrlen = sizeof(struct sockaddr_storage);
  1.1398 +		r = recvfrom(s->socket, (void*)packet, sizeof(packet), 0,
  1.1399 +					 (struct sockaddr*) &addr, &addrlen);
  1.1400 +		if (r < 0) {
  1.1401 +			int err = evutil_socket_geterror(s->socket);
  1.1402 +			if (EVUTIL_ERR_RW_RETRIABLE(err))
  1.1403 +				return;
  1.1404 +			log(EVDNS_LOG_WARN,
  1.1405 +			    "Error %s (%d) while reading request.",
  1.1406 +			    evutil_socket_error_to_string(err), err);
  1.1407 +			return;
  1.1408 +		}
  1.1409 +		request_parse(packet, r, s, (struct sockaddr*) &addr, addrlen);
  1.1410 +	}
  1.1411 +}
  1.1412 +
  1.1413 +/* Try to write all pending replies on a given DNS server port. */
  1.1414 +static void
  1.1415 +server_port_flush(struct evdns_server_port *port)
  1.1416 +{
  1.1417 +	struct server_request *req = port->pending_replies;
  1.1418 +	ASSERT_LOCKED(port);
  1.1419 +	while (req) {
  1.1420 +		int r = sendto(port->socket, req->response, (int)req->response_len, 0,
  1.1421 +			   (struct sockaddr*) &req->addr, (ev_socklen_t)req->addrlen);
  1.1422 +		if (r < 0) {
  1.1423 +			int err = evutil_socket_geterror(port->socket);
  1.1424 +			if (EVUTIL_ERR_RW_RETRIABLE(err))
  1.1425 +				return;
  1.1426 +			log(EVDNS_LOG_WARN, "Error %s (%d) while writing response to port; dropping", evutil_socket_error_to_string(err), err);
  1.1427 +		}
  1.1428 +		if (server_request_free(req)) {
  1.1429 +			/* we released the last reference to req->port. */
  1.1430 +			return;
  1.1431 +		} else {
  1.1432 +			EVUTIL_ASSERT(req != port->pending_replies);
  1.1433 +			req = port->pending_replies;
  1.1434 +		}
  1.1435 +	}
  1.1436 +
  1.1437 +	/* We have no more pending requests; stop listening for 'writeable' events. */
  1.1438 +	(void) event_del(&port->event);
  1.1439 +	event_assign(&port->event, port->event_base,
  1.1440 +				 port->socket, EV_READ | EV_PERSIST,
  1.1441 +				 server_port_ready_callback, port);
  1.1442 +
  1.1443 +	if (event_add(&port->event, NULL) < 0) {
  1.1444 +		log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server.");
  1.1445 +		/* ???? Do more? */
  1.1446 +	}
  1.1447 +}
  1.1448 +
  1.1449 +/* set if we are waiting for the ability to write to this server. */
  1.1450 +/* if waiting is true then we ask libevent for EV_WRITE events, otherwise */
  1.1451 +/* we stop these events. */
  1.1452 +static void
  1.1453 +nameserver_write_waiting(struct nameserver *ns, char waiting) {
  1.1454 +	ASSERT_LOCKED(ns->base);
  1.1455 +	if (ns->write_waiting == waiting) return;
  1.1456 +
  1.1457 +	ns->write_waiting = waiting;
  1.1458 +	(void) event_del(&ns->event);
  1.1459 +	event_assign(&ns->event, ns->base->event_base,
  1.1460 +	    ns->socket, EV_READ | (waiting ? EV_WRITE : 0) | EV_PERSIST,
  1.1461 +	    nameserver_ready_callback, ns);
  1.1462 +	if (event_add(&ns->event, NULL) < 0) {
  1.1463 +		char addrbuf[128];
  1.1464 +		log(EVDNS_LOG_WARN, "Error from libevent when adding event for %s",
  1.1465 +		    evutil_format_sockaddr_port(
  1.1466 +			    (struct sockaddr *)&ns->address,
  1.1467 +			    addrbuf, sizeof(addrbuf)));
  1.1468 +		/* ???? Do more? */
  1.1469 +	}
  1.1470 +}
  1.1471 +
  1.1472 +/* a callback function. Called by libevent when the kernel says that */
  1.1473 +/* a nameserver socket is ready for writing or reading */
  1.1474 +static void
  1.1475 +nameserver_ready_callback(evutil_socket_t fd, short events, void *arg) {
  1.1476 +	struct nameserver *ns = (struct nameserver *) arg;
  1.1477 +	(void)fd;
  1.1478 +
  1.1479 +	EVDNS_LOCK(ns->base);
  1.1480 +	if (events & EV_WRITE) {
  1.1481 +		ns->choked = 0;
  1.1482 +		if (!evdns_transmit(ns->base)) {
  1.1483 +			nameserver_write_waiting(ns, 0);
  1.1484 +		}
  1.1485 +	}
  1.1486 +	if (events & EV_READ) {
  1.1487 +		nameserver_read(ns);
  1.1488 +	}
  1.1489 +	EVDNS_UNLOCK(ns->base);
  1.1490 +}
  1.1491 +
  1.1492 +/* a callback function. Called by libevent when the kernel says that */
  1.1493 +/* a server socket is ready for writing or reading. */
  1.1494 +static void
  1.1495 +server_port_ready_callback(evutil_socket_t fd, short events, void *arg) {
  1.1496 +	struct evdns_server_port *port = (struct evdns_server_port *) arg;
  1.1497 +	(void) fd;
  1.1498 +
  1.1499 +	EVDNS_LOCK(port);
  1.1500 +	if (events & EV_WRITE) {
  1.1501 +		port->choked = 0;
  1.1502 +		server_port_flush(port);
  1.1503 +	}
  1.1504 +	if (events & EV_READ) {
  1.1505 +		server_port_read(port);
  1.1506 +	}
  1.1507 +	EVDNS_UNLOCK(port);
  1.1508 +}
  1.1509 +
  1.1510 +/* This is an inefficient representation; only use it via the dnslabel_table_*
  1.1511 + * functions, so that is can be safely replaced with something smarter later. */
  1.1512 +#define MAX_LABELS 128
  1.1513 +/* Structures used to implement name compression */
  1.1514 +struct dnslabel_entry { char *v; off_t pos; };
  1.1515 +struct dnslabel_table {
  1.1516 +	int n_labels; /* number of current entries */
  1.1517 +	/* map from name to position in message */
  1.1518 +	struct dnslabel_entry labels[MAX_LABELS];
  1.1519 +};
  1.1520 +
  1.1521 +/* Initialize dnslabel_table. */
  1.1522 +static void
  1.1523 +dnslabel_table_init(struct dnslabel_table *table)
  1.1524 +{
  1.1525 +	table->n_labels = 0;
  1.1526 +}
  1.1527 +
  1.1528 +/* Free all storage held by table, but not the table itself. */
  1.1529 +static void
  1.1530 +dnslabel_clear(struct dnslabel_table *table)
  1.1531 +{
  1.1532 +	int i;
  1.1533 +	for (i = 0; i < table->n_labels; ++i)
  1.1534 +		mm_free(table->labels[i].v);
  1.1535 +	table->n_labels = 0;
  1.1536 +}
  1.1537 +
  1.1538 +/* return the position of the label in the current message, or -1 if the label */
  1.1539 +/* hasn't been used yet. */
  1.1540 +static int
  1.1541 +dnslabel_table_get_pos(const struct dnslabel_table *table, const char *label)
  1.1542 +{
  1.1543 +	int i;
  1.1544 +	for (i = 0; i < table->n_labels; ++i) {
  1.1545 +		if (!strcmp(label, table->labels[i].v))
  1.1546 +			return table->labels[i].pos;
  1.1547 +	}
  1.1548 +	return -1;
  1.1549 +}
  1.1550 +
  1.1551 +/* remember that we've used the label at position pos */
  1.1552 +static int
  1.1553 +dnslabel_table_add(struct dnslabel_table *table, const char *label, off_t pos)
  1.1554 +{
  1.1555 +	char *v;
  1.1556 +	int p;
  1.1557 +	if (table->n_labels == MAX_LABELS)
  1.1558 +		return (-1);
  1.1559 +	v = mm_strdup(label);
  1.1560 +	if (v == NULL)
  1.1561 +		return (-1);
  1.1562 +	p = table->n_labels++;
  1.1563 +	table->labels[p].v = v;
  1.1564 +	table->labels[p].pos = pos;
  1.1565 +
  1.1566 +	return (0);
  1.1567 +}
  1.1568 +
  1.1569 +/* Converts a string to a length-prefixed set of DNS labels, starting */
  1.1570 +/* at buf[j]. name and buf must not overlap. name_len should be the length */
  1.1571 +/* of name.	 table is optional, and is used for compression. */
  1.1572 +/* */
  1.1573 +/* Input: abc.def */
  1.1574 +/* Output: <3>abc<3>def<0> */
  1.1575 +/* */
  1.1576 +/* Returns the first index after the encoded name, or negative on error. */
  1.1577 +/*	 -1	 label was > 63 bytes */
  1.1578 +/*	 -2	 name too long to fit in buffer. */
  1.1579 +/* */
  1.1580 +static off_t
  1.1581 +dnsname_to_labels(u8 *const buf, size_t buf_len, off_t j,
  1.1582 +				  const char *name, const size_t name_len,
  1.1583 +				  struct dnslabel_table *table) {
  1.1584 +	const char *end = name + name_len;
  1.1585 +	int ref = 0;
  1.1586 +	u16 _t;
  1.1587 +
  1.1588 +#define APPEND16(x) do {						\
  1.1589 +		if (j + 2 > (off_t)buf_len)				\
  1.1590 +			goto overflow;					\
  1.1591 +		_t = htons(x);						\
  1.1592 +		memcpy(buf + j, &_t, 2);				\
  1.1593 +		j += 2;							\
  1.1594 +	} while (0)
  1.1595 +#define APPEND32(x) do {						\
  1.1596 +		if (j + 4 > (off_t)buf_len)				\
  1.1597 +			goto overflow;					\
  1.1598 +		_t32 = htonl(x);					\
  1.1599 +		memcpy(buf + j, &_t32, 4);				\
  1.1600 +		j += 4;							\
  1.1601 +	} while (0)
  1.1602 +
  1.1603 +	if (name_len > 255) return -2;
  1.1604 +
  1.1605 +	for (;;) {
  1.1606 +		const char *const start = name;
  1.1607 +		if (table && (ref = dnslabel_table_get_pos(table, name)) >= 0) {
  1.1608 +			APPEND16(ref | 0xc000);
  1.1609 +			return j;
  1.1610 +		}
  1.1611 +		name = strchr(name, '.');
  1.1612 +		if (!name) {
  1.1613 +			const size_t label_len = end - start;
  1.1614 +			if (label_len > 63) return -1;
  1.1615 +			if ((size_t)(j+label_len+1) > buf_len) return -2;
  1.1616 +			if (table) dnslabel_table_add(table, start, j);
  1.1617 +			buf[j++] = (ev_uint8_t)label_len;
  1.1618 +
  1.1619 +			memcpy(buf + j, start, label_len);
  1.1620 +			j += (int) label_len;
  1.1621 +			break;
  1.1622 +		} else {
  1.1623 +			/* append length of the label. */
  1.1624 +			const size_t label_len = name - start;
  1.1625 +			if (label_len > 63) return -1;
  1.1626 +			if ((size_t)(j+label_len+1) > buf_len) return -2;
  1.1627 +			if (table) dnslabel_table_add(table, start, j);
  1.1628 +			buf[j++] = (ev_uint8_t)label_len;
  1.1629 +
  1.1630 +			memcpy(buf + j, start, label_len);
  1.1631 +			j += (int) label_len;
  1.1632 +			/* hop over the '.' */
  1.1633 +			name++;
  1.1634 +		}
  1.1635 +	}
  1.1636 +
  1.1637 +	/* the labels must be terminated by a 0. */
  1.1638 +	/* It's possible that the name ended in a . */
  1.1639 +	/* in which case the zero is already there */
  1.1640 +	if (!j || buf[j-1]) buf[j++] = 0;
  1.1641 +	return j;
  1.1642 + overflow:
  1.1643 +	return (-2);
  1.1644 +}
  1.1645 +
  1.1646 +/* Finds the length of a dns request for a DNS name of the given */
  1.1647 +/* length. The actual request may be smaller than the value returned */
  1.1648 +/* here */
  1.1649 +static size_t
  1.1650 +evdns_request_len(const size_t name_len) {
  1.1651 +	return 96 + /* length of the DNS standard header */
  1.1652 +		name_len + 2 +
  1.1653 +		4;  /* space for the resource type */
  1.1654 +}
  1.1655 +
  1.1656 +/* build a dns request packet into buf. buf should be at least as long */
  1.1657 +/* as evdns_request_len told you it should be. */
  1.1658 +/* */
  1.1659 +/* Returns the amount of space used. Negative on error. */
  1.1660 +static int
  1.1661 +evdns_request_data_build(const char *const name, const size_t name_len,
  1.1662 +    const u16 trans_id, const u16 type, const u16 class,
  1.1663 +    u8 *const buf, size_t buf_len) {
  1.1664 +	off_t j = 0;  /* current offset into buf */
  1.1665 +	u16 _t;	 /* used by the macros */
  1.1666 +
  1.1667 +	APPEND16(trans_id);
  1.1668 +	APPEND16(0x0100);  /* standard query, recusion needed */
  1.1669 +	APPEND16(1);  /* one question */
  1.1670 +	APPEND16(0);  /* no answers */
  1.1671 +	APPEND16(0);  /* no authority */
  1.1672 +	APPEND16(0);  /* no additional */
  1.1673 +
  1.1674 +	j = dnsname_to_labels(buf, buf_len, j, name, name_len, NULL);
  1.1675 +	if (j < 0) {
  1.1676 +		return (int)j;
  1.1677 +	}
  1.1678 +
  1.1679 +	APPEND16(type);
  1.1680 +	APPEND16(class);
  1.1681 +
  1.1682 +	return (int)j;
  1.1683 + overflow:
  1.1684 +	return (-1);
  1.1685 +}
  1.1686 +
  1.1687 +/* exported function */
  1.1688 +struct evdns_server_port *
  1.1689 +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)
  1.1690 +{
  1.1691 +	struct evdns_server_port *port;
  1.1692 +	if (flags)
  1.1693 +		return NULL; /* flags not yet implemented */
  1.1694 +	if (!(port = mm_malloc(sizeof(struct evdns_server_port))))
  1.1695 +		return NULL;
  1.1696 +	memset(port, 0, sizeof(struct evdns_server_port));
  1.1697 +
  1.1698 +
  1.1699 +	port->socket = socket;
  1.1700 +	port->refcnt = 1;
  1.1701 +	port->choked = 0;
  1.1702 +	port->closing = 0;
  1.1703 +	port->user_callback = cb;
  1.1704 +	port->user_data = user_data;
  1.1705 +	port->pending_replies = NULL;
  1.1706 +	port->event_base = base;
  1.1707 +
  1.1708 +	event_assign(&port->event, port->event_base,
  1.1709 +				 port->socket, EV_READ | EV_PERSIST,
  1.1710 +				 server_port_ready_callback, port);
  1.1711 +	if (event_add(&port->event, NULL) < 0) {
  1.1712 +		mm_free(port);
  1.1713 +		return NULL;
  1.1714 +	}
  1.1715 +	EVTHREAD_ALLOC_LOCK(port->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
  1.1716 +	return port;
  1.1717 +}
  1.1718 +
  1.1719 +struct evdns_server_port *
  1.1720 +evdns_add_server_port(evutil_socket_t socket, int flags, evdns_request_callback_fn_type cb, void *user_data)
  1.1721 +{
  1.1722 +	return evdns_add_server_port_with_base(NULL, socket, flags, cb, user_data);
  1.1723 +}
  1.1724 +
  1.1725 +/* exported function */
  1.1726 +void
  1.1727 +evdns_close_server_port(struct evdns_server_port *port)
  1.1728 +{
  1.1729 +	EVDNS_LOCK(port);
  1.1730 +	if (--port->refcnt == 0) {
  1.1731 +		EVDNS_UNLOCK(port);
  1.1732 +		server_port_free(port);
  1.1733 +	} else {
  1.1734 +		port->closing = 1;
  1.1735 +	}
  1.1736 +}
  1.1737 +
  1.1738 +/* exported function */
  1.1739 +int
  1.1740 +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)
  1.1741 +{
  1.1742 +	struct server_request *req = TO_SERVER_REQUEST(_req);
  1.1743 +	struct server_reply_item **itemp, *item;
  1.1744 +	int *countp;
  1.1745 +	int result = -1;
  1.1746 +
  1.1747 +	EVDNS_LOCK(req->port);
  1.1748 +	if (req->response) /* have we already answered? */
  1.1749 +		goto done;
  1.1750 +
  1.1751 +	switch (section) {
  1.1752 +	case EVDNS_ANSWER_SECTION:
  1.1753 +		itemp = &req->answer;
  1.1754 +		countp = &req->n_answer;
  1.1755 +		break;
  1.1756 +	case EVDNS_AUTHORITY_SECTION:
  1.1757 +		itemp = &req->authority;
  1.1758 +		countp = &req->n_authority;
  1.1759 +		break;
  1.1760 +	case EVDNS_ADDITIONAL_SECTION:
  1.1761 +		itemp = &req->additional;
  1.1762 +		countp = &req->n_additional;
  1.1763 +		break;
  1.1764 +	default:
  1.1765 +		goto done;
  1.1766 +	}
  1.1767 +	while (*itemp) {
  1.1768 +		itemp = &((*itemp)->next);
  1.1769 +	}
  1.1770 +	item = mm_malloc(sizeof(struct server_reply_item));
  1.1771 +	if (!item)
  1.1772 +		goto done;
  1.1773 +	item->next = NULL;
  1.1774 +	if (!(item->name = mm_strdup(name))) {
  1.1775 +		mm_free(item);
  1.1776 +		goto done;
  1.1777 +	}
  1.1778 +	item->type = type;
  1.1779 +	item->dns_question_class = class;
  1.1780 +	item->ttl = ttl;
  1.1781 +	item->is_name = is_name != 0;
  1.1782 +	item->datalen = 0;
  1.1783 +	item->data = NULL;
  1.1784 +	if (data) {
  1.1785 +		if (item->is_name) {
  1.1786 +			if (!(item->data = mm_strdup(data))) {
  1.1787 +				mm_free(item->name);
  1.1788 +				mm_free(item);
  1.1789 +				goto done;
  1.1790 +			}
  1.1791 +			item->datalen = (u16)-1;
  1.1792 +		} else {
  1.1793 +			if (!(item->data = mm_malloc(datalen))) {
  1.1794 +				mm_free(item->name);
  1.1795 +				mm_free(item);
  1.1796 +				goto done;
  1.1797 +			}
  1.1798 +			item->datalen = datalen;
  1.1799 +			memcpy(item->data, data, datalen);
  1.1800 +		}
  1.1801 +	}
  1.1802 +
  1.1803 +	*itemp = item;
  1.1804 +	++(*countp);
  1.1805 +	result = 0;
  1.1806 +done:
  1.1807 +	EVDNS_UNLOCK(req->port);
  1.1808 +	return result;
  1.1809 +}
  1.1810 +
  1.1811 +/* exported function */
  1.1812 +int
  1.1813 +evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl)
  1.1814 +{
  1.1815 +	return evdns_server_request_add_reply(
  1.1816 +		  req, EVDNS_ANSWER_SECTION, name, TYPE_A, CLASS_INET,
  1.1817 +		  ttl, n*4, 0, addrs);
  1.1818 +}
  1.1819 +
  1.1820 +/* exported function */
  1.1821 +int
  1.1822 +evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, const void *addrs, int ttl)
  1.1823 +{
  1.1824 +	return evdns_server_request_add_reply(
  1.1825 +		  req, EVDNS_ANSWER_SECTION, name, TYPE_AAAA, CLASS_INET,
  1.1826 +		  ttl, n*16, 0, addrs);
  1.1827 +}
  1.1828 +
  1.1829 +/* exported function */
  1.1830 +int
  1.1831 +evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl)
  1.1832 +{
  1.1833 +	u32 a;
  1.1834 +	char buf[32];
  1.1835 +	if (in && inaddr_name)
  1.1836 +		return -1;
  1.1837 +	else if (!in && !inaddr_name)
  1.1838 +		return -1;
  1.1839 +	if (in) {
  1.1840 +		a = ntohl(in->s_addr);
  1.1841 +		evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
  1.1842 +				(int)(u8)((a	)&0xff),
  1.1843 +				(int)(u8)((a>>8 )&0xff),
  1.1844 +				(int)(u8)((a>>16)&0xff),
  1.1845 +				(int)(u8)((a>>24)&0xff));
  1.1846 +		inaddr_name = buf;
  1.1847 +	}
  1.1848 +	return evdns_server_request_add_reply(
  1.1849 +		  req, EVDNS_ANSWER_SECTION, inaddr_name, TYPE_PTR, CLASS_INET,
  1.1850 +		  ttl, -1, 1, hostname);
  1.1851 +}
  1.1852 +
  1.1853 +/* exported function */
  1.1854 +int
  1.1855 +evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl)
  1.1856 +{
  1.1857 +	return evdns_server_request_add_reply(
  1.1858 +		  req, EVDNS_ANSWER_SECTION, name, TYPE_CNAME, CLASS_INET,
  1.1859 +		  ttl, -1, 1, cname);
  1.1860 +}
  1.1861 +
  1.1862 +/* exported function */
  1.1863 +void
  1.1864 +evdns_server_request_set_flags(struct evdns_server_request *exreq, int flags)
  1.1865 +{
  1.1866 +	struct server_request *req = TO_SERVER_REQUEST(exreq);
  1.1867 +	req->base.flags &= ~(EVDNS_FLAGS_AA|EVDNS_FLAGS_RD);
  1.1868 +	req->base.flags |= flags;
  1.1869 +}
  1.1870 +
  1.1871 +static int
  1.1872 +evdns_server_request_format_response(struct server_request *req, int err)
  1.1873 +{
  1.1874 +	unsigned char buf[1500];
  1.1875 +	size_t buf_len = sizeof(buf);
  1.1876 +	off_t j = 0, r;
  1.1877 +	u16 _t;
  1.1878 +	u32 _t32;
  1.1879 +	int i;
  1.1880 +	u16 flags;
  1.1881 +	struct dnslabel_table table;
  1.1882 +
  1.1883 +	if (err < 0 || err > 15) return -1;
  1.1884 +
  1.1885 +	/* Set response bit and error code; copy OPCODE and RD fields from
  1.1886 +	 * question; copy RA and AA if set by caller. */
  1.1887 +	flags = req->base.flags;
  1.1888 +	flags |= (0x8000 | err);
  1.1889 +
  1.1890 +	dnslabel_table_init(&table);
  1.1891 +	APPEND16(req->trans_id);
  1.1892 +	APPEND16(flags);
  1.1893 +	APPEND16(req->base.nquestions);
  1.1894 +	APPEND16(req->n_answer);
  1.1895 +	APPEND16(req->n_authority);
  1.1896 +	APPEND16(req->n_additional);
  1.1897 +
  1.1898 +	/* Add questions. */
  1.1899 +	for (i=0; i < req->base.nquestions; ++i) {
  1.1900 +		const char *s = req->base.questions[i]->name;
  1.1901 +		j = dnsname_to_labels(buf, buf_len, j, s, strlen(s), &table);
  1.1902 +		if (j < 0) {
  1.1903 +			dnslabel_clear(&table);
  1.1904 +			return (int) j;
  1.1905 +		}
  1.1906 +		APPEND16(req->base.questions[i]->type);
  1.1907 +		APPEND16(req->base.questions[i]->dns_question_class);
  1.1908 +	}
  1.1909 +
  1.1910 +	/* Add answer, authority, and additional sections. */
  1.1911 +	for (i=0; i<3; ++i) {
  1.1912 +		struct server_reply_item *item;
  1.1913 +		if (i==0)
  1.1914 +			item = req->answer;
  1.1915 +		else if (i==1)
  1.1916 +			item = req->authority;
  1.1917 +		else
  1.1918 +			item = req->additional;
  1.1919 +		while (item) {
  1.1920 +			r = dnsname_to_labels(buf, buf_len, j, item->name, strlen(item->name), &table);
  1.1921 +			if (r < 0)
  1.1922 +				goto overflow;
  1.1923 +			j = r;
  1.1924 +
  1.1925 +			APPEND16(item->type);
  1.1926 +			APPEND16(item->dns_question_class);
  1.1927 +			APPEND32(item->ttl);
  1.1928 +			if (item->is_name) {
  1.1929 +				off_t len_idx = j, name_start;
  1.1930 +				j += 2;
  1.1931 +				name_start = j;
  1.1932 +				r = dnsname_to_labels(buf, buf_len, j, item->data, strlen(item->data), &table);
  1.1933 +				if (r < 0)
  1.1934 +					goto overflow;
  1.1935 +				j = r;
  1.1936 +				_t = htons( (short) (j-name_start) );
  1.1937 +				memcpy(buf+len_idx, &_t, 2);
  1.1938 +			} else {
  1.1939 +				APPEND16(item->datalen);
  1.1940 +				if (j+item->datalen > (off_t)buf_len)
  1.1941 +					goto overflow;
  1.1942 +				memcpy(buf+j, item->data, item->datalen);
  1.1943 +				j += item->datalen;
  1.1944 +			}
  1.1945 +			item = item->next;
  1.1946 +		}
  1.1947 +	}
  1.1948 +
  1.1949 +	if (j > 512) {
  1.1950 +overflow:
  1.1951 +		j = 512;
  1.1952 +		buf[2] |= 0x02; /* set the truncated bit. */
  1.1953 +	}
  1.1954 +
  1.1955 +	req->response_len = j;
  1.1956 +
  1.1957 +	if (!(req->response = mm_malloc(req->response_len))) {
  1.1958 +		server_request_free_answers(req);
  1.1959 +		dnslabel_clear(&table);
  1.1960 +		return (-1);
  1.1961 +	}
  1.1962 +	memcpy(req->response, buf, req->response_len);
  1.1963 +	server_request_free_answers(req);
  1.1964 +	dnslabel_clear(&table);
  1.1965 +	return (0);
  1.1966 +}
  1.1967 +
  1.1968 +/* exported function */
  1.1969 +int
  1.1970 +evdns_server_request_respond(struct evdns_server_request *_req, int err)
  1.1971 +{
  1.1972 +	struct server_request *req = TO_SERVER_REQUEST(_req);
  1.1973 +	struct evdns_server_port *port = req->port;
  1.1974 +	int r = -1;
  1.1975 +
  1.1976 +	EVDNS_LOCK(port);
  1.1977 +	if (!req->response) {
  1.1978 +		if ((r = evdns_server_request_format_response(req, err))<0)
  1.1979 +			goto done;
  1.1980 +	}
  1.1981 +
  1.1982 +	r = sendto(port->socket, req->response, (int)req->response_len, 0,
  1.1983 +			   (struct sockaddr*) &req->addr, (ev_socklen_t)req->addrlen);
  1.1984 +	if (r<0) {
  1.1985 +		int sock_err = evutil_socket_geterror(port->socket);
  1.1986 +		if (EVUTIL_ERR_RW_RETRIABLE(sock_err))
  1.1987 +			goto done;
  1.1988 +
  1.1989 +		if (port->pending_replies) {
  1.1990 +			req->prev_pending = port->pending_replies->prev_pending;
  1.1991 +			req->next_pending = port->pending_replies;
  1.1992 +			req->prev_pending->next_pending =
  1.1993 +				req->next_pending->prev_pending = req;
  1.1994 +		} else {
  1.1995 +			req->prev_pending = req->next_pending = req;
  1.1996 +			port->pending_replies = req;
  1.1997 +			port->choked = 1;
  1.1998 +
  1.1999 +			(void) event_del(&port->event);
  1.2000 +			event_assign(&port->event, port->event_base, port->socket, (port->closing?0:EV_READ) | EV_WRITE | EV_PERSIST, server_port_ready_callback, port);
  1.2001 +
  1.2002 +			if (event_add(&port->event, NULL) < 0) {
  1.2003 +				log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server");
  1.2004 +			}
  1.2005 +
  1.2006 +		}
  1.2007 +
  1.2008 +		r = 1;
  1.2009 +		goto done;
  1.2010 +	}
  1.2011 +	if (server_request_free(req)) {
  1.2012 +		r = 0;
  1.2013 +		goto done;
  1.2014 +	}
  1.2015 +
  1.2016 +	if (port->pending_replies)
  1.2017 +		server_port_flush(port);
  1.2018 +
  1.2019 +	r = 0;
  1.2020 +done:
  1.2021 +	EVDNS_UNLOCK(port);
  1.2022 +	return r;
  1.2023 +}
  1.2024 +
  1.2025 +/* Free all storage held by RRs in req. */
  1.2026 +static void
  1.2027 +server_request_free_answers(struct server_request *req)
  1.2028 +{
  1.2029 +	struct server_reply_item *victim, *next, **list;
  1.2030 +	int i;
  1.2031 +	for (i = 0; i < 3; ++i) {
  1.2032 +		if (i==0)
  1.2033 +			list = &req->answer;
  1.2034 +		else if (i==1)
  1.2035 +			list = &req->authority;
  1.2036 +		else
  1.2037 +			list = &req->additional;
  1.2038 +
  1.2039 +		victim = *list;
  1.2040 +		while (victim) {
  1.2041 +			next = victim->next;
  1.2042 +			mm_free(victim->name);
  1.2043 +			if (victim->data)
  1.2044 +				mm_free(victim->data);
  1.2045 +			mm_free(victim);
  1.2046 +			victim = next;
  1.2047 +		}
  1.2048 +		*list = NULL;
  1.2049 +	}
  1.2050 +}
  1.2051 +
  1.2052 +/* Free all storage held by req, and remove links to it. */
  1.2053 +/* return true iff we just wound up freeing the server_port. */
  1.2054 +static int
  1.2055 +server_request_free(struct server_request *req)
  1.2056 +{
  1.2057 +	int i, rc=1, lock=0;
  1.2058 +	if (req->base.questions) {
  1.2059 +		for (i = 0; i < req->base.nquestions; ++i)
  1.2060 +			mm_free(req->base.questions[i]);
  1.2061 +		mm_free(req->base.questions);
  1.2062 +	}
  1.2063 +
  1.2064 +	if (req->port) {
  1.2065 +		EVDNS_LOCK(req->port);
  1.2066 +		lock=1;
  1.2067 +		if (req->port->pending_replies == req) {
  1.2068 +			if (req->next_pending && req->next_pending != req)
  1.2069 +				req->port->pending_replies = req->next_pending;
  1.2070 +			else
  1.2071 +				req->port->pending_replies = NULL;
  1.2072 +		}
  1.2073 +		rc = --req->port->refcnt;
  1.2074 +	}
  1.2075 +
  1.2076 +	if (req->response) {
  1.2077 +		mm_free(req->response);
  1.2078 +	}
  1.2079 +
  1.2080 +	server_request_free_answers(req);
  1.2081 +
  1.2082 +	if (req->next_pending && req->next_pending != req) {
  1.2083 +		req->next_pending->prev_pending = req->prev_pending;
  1.2084 +		req->prev_pending->next_pending = req->next_pending;
  1.2085 +	}
  1.2086 +
  1.2087 +	if (rc == 0) {
  1.2088 +		EVDNS_UNLOCK(req->port); /* ????? nickm */
  1.2089 +		server_port_free(req->port);
  1.2090 +		mm_free(req);
  1.2091 +		return (1);
  1.2092 +	}
  1.2093 +	if (lock)
  1.2094 +		EVDNS_UNLOCK(req->port);
  1.2095 +	mm_free(req);
  1.2096 +	return (0);
  1.2097 +}
  1.2098 +
  1.2099 +/* Free all storage held by an evdns_server_port.  Only called when  */
  1.2100 +static void
  1.2101 +server_port_free(struct evdns_server_port *port)
  1.2102 +{
  1.2103 +	EVUTIL_ASSERT(port);
  1.2104 +	EVUTIL_ASSERT(!port->refcnt);
  1.2105 +	EVUTIL_ASSERT(!port->pending_replies);
  1.2106 +	if (port->socket > 0) {
  1.2107 +		evutil_closesocket(port->socket);
  1.2108 +		port->socket = -1;
  1.2109 +	}
  1.2110 +	(void) event_del(&port->event);
  1.2111 +	event_debug_unassign(&port->event);
  1.2112 +	EVTHREAD_FREE_LOCK(port->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
  1.2113 +	mm_free(port);
  1.2114 +}
  1.2115 +
  1.2116 +/* exported function */
  1.2117 +int
  1.2118 +evdns_server_request_drop(struct evdns_server_request *_req)
  1.2119 +{
  1.2120 +	struct server_request *req = TO_SERVER_REQUEST(_req);
  1.2121 +	server_request_free(req);
  1.2122 +	return 0;
  1.2123 +}
  1.2124 +
  1.2125 +/* exported function */
  1.2126 +int
  1.2127 +evdns_server_request_get_requesting_addr(struct evdns_server_request *_req, struct sockaddr *sa, int addr_len)
  1.2128 +{
  1.2129 +	struct server_request *req = TO_SERVER_REQUEST(_req);
  1.2130 +	if (addr_len < (int)req->addrlen)
  1.2131 +		return -1;
  1.2132 +	memcpy(sa, &(req->addr), req->addrlen);
  1.2133 +	return req->addrlen;
  1.2134 +}
  1.2135 +
  1.2136 +#undef APPEND16
  1.2137 +#undef APPEND32
  1.2138 +
  1.2139 +/* this is a libevent callback function which is called when a request */
  1.2140 +/* has timed out. */
  1.2141 +static void
  1.2142 +evdns_request_timeout_callback(evutil_socket_t fd, short events, void *arg) {
  1.2143 +	struct request *const req = (struct request *) arg;
  1.2144 +	struct evdns_base *base = req->base;
  1.2145 +
  1.2146 +	(void) fd;
  1.2147 +	(void) events;
  1.2148 +
  1.2149 +	log(EVDNS_LOG_DEBUG, "Request %p timed out", arg);
  1.2150 +	EVDNS_LOCK(base);
  1.2151 +
  1.2152 +	req->ns->timedout++;
  1.2153 +	if (req->ns->timedout > req->base->global_max_nameserver_timeout) {
  1.2154 +		req->ns->timedout = 0;
  1.2155 +		nameserver_failed(req->ns, "request timed out.");
  1.2156 +	}
  1.2157 +
  1.2158 +	if (req->tx_count >= req->base->global_max_retransmits) {
  1.2159 +		/* this request has failed */
  1.2160 +		log(EVDNS_LOG_DEBUG, "Giving up on request %p; tx_count==%d",
  1.2161 +		    arg, req->tx_count);
  1.2162 +		reply_schedule_callback(req, 0, DNS_ERR_TIMEOUT, NULL);
  1.2163 +		request_finished(req, &REQ_HEAD(req->base, req->trans_id), 1);
  1.2164 +	} else {
  1.2165 +		/* retransmit it */
  1.2166 +		struct nameserver *new_ns;
  1.2167 +		log(EVDNS_LOG_DEBUG, "Retransmitting request %p; tx_count==%d",
  1.2168 +		    arg, req->tx_count);
  1.2169 +		(void) evtimer_del(&req->timeout_event);
  1.2170 +		new_ns = nameserver_pick(base);
  1.2171 +		if (new_ns)
  1.2172 +			req->ns = new_ns;
  1.2173 +		evdns_request_transmit(req);
  1.2174 +	}
  1.2175 +	EVDNS_UNLOCK(base);
  1.2176 +}
  1.2177 +
  1.2178 +/* try to send a request to a given server. */
  1.2179 +/* */
  1.2180 +/* return: */
  1.2181 +/*   0 ok */
  1.2182 +/*   1 temporary failure */
  1.2183 +/*   2 other failure */
  1.2184 +static int
  1.2185 +evdns_request_transmit_to(struct request *req, struct nameserver *server) {
  1.2186 +	int r;
  1.2187 +	ASSERT_LOCKED(req->base);
  1.2188 +	ASSERT_VALID_REQUEST(req);
  1.2189 +	r = sendto(server->socket, (void*)req->request, req->request_len, 0,
  1.2190 +	    (struct sockaddr *)&server->address, server->addrlen);
  1.2191 +	if (r < 0) {
  1.2192 +		int err = evutil_socket_geterror(server->socket);
  1.2193 +		if (EVUTIL_ERR_RW_RETRIABLE(err))
  1.2194 +			return 1;
  1.2195 +		nameserver_failed(req->ns, evutil_socket_error_to_string(err));
  1.2196 +		return 2;
  1.2197 +	} else if (r != (int)req->request_len) {
  1.2198 +		return 1;  /* short write */
  1.2199 +	} else {
  1.2200 +		return 0;
  1.2201 +	}
  1.2202 +}
  1.2203 +
  1.2204 +/* try to send a request, updating the fields of the request */
  1.2205 +/* as needed */
  1.2206 +/* */
  1.2207 +/* return: */
  1.2208 +/*   0 ok */
  1.2209 +/*   1 failed */
  1.2210 +static int
  1.2211 +evdns_request_transmit(struct request *req) {
  1.2212 +	int retcode = 0, r;
  1.2213 +
  1.2214 +	ASSERT_LOCKED(req->base);
  1.2215 +	ASSERT_VALID_REQUEST(req);
  1.2216 +	/* if we fail to send this packet then this flag marks it */
  1.2217 +	/* for evdns_transmit */
  1.2218 +	req->transmit_me = 1;
  1.2219 +	EVUTIL_ASSERT(req->trans_id != 0xffff);
  1.2220 +
  1.2221 +	if (req->ns->choked) {
  1.2222 +		/* don't bother trying to write to a socket */
  1.2223 +		/* which we have had EAGAIN from */
  1.2224 +		return 1;
  1.2225 +	}
  1.2226 +
  1.2227 +	r = evdns_request_transmit_to(req, req->ns);
  1.2228 +	switch (r) {
  1.2229 +	case 1:
  1.2230 +		/* temp failure */
  1.2231 +		req->ns->choked = 1;
  1.2232 +		nameserver_write_waiting(req->ns, 1);
  1.2233 +		return 1;
  1.2234 +	case 2:
  1.2235 +		/* failed to transmit the request entirely. */
  1.2236 +		retcode = 1;
  1.2237 +		/* fall through: we'll set a timeout, which will time out,
  1.2238 +		 * and make us retransmit the request anyway. */
  1.2239 +	default:
  1.2240 +		/* all ok */
  1.2241 +		log(EVDNS_LOG_DEBUG,
  1.2242 +		    "Setting timeout for request %p, sent to nameserver %p", req, req->ns);
  1.2243 +		if (evtimer_add(&req->timeout_event, &req->base->global_timeout) < 0) {
  1.2244 +			log(EVDNS_LOG_WARN,
  1.2245 +		      "Error from libevent when adding timer for request %p",
  1.2246 +			    req);
  1.2247 +			/* ???? Do more? */
  1.2248 +		}
  1.2249 +		req->tx_count++;
  1.2250 +		req->transmit_me = 0;
  1.2251 +		return retcode;
  1.2252 +	}
  1.2253 +}
  1.2254 +
  1.2255 +static void
  1.2256 +nameserver_probe_callback(int result, char type, int count, int ttl, void *addresses, void *arg) {
  1.2257 +	struct nameserver *const ns = (struct nameserver *) arg;
  1.2258 +	(void) type;
  1.2259 +	(void) count;
  1.2260 +	(void) ttl;
  1.2261 +	(void) addresses;
  1.2262 +
  1.2263 +	if (result == DNS_ERR_CANCEL) {
  1.2264 +		/* We canceled this request because the nameserver came up
  1.2265 +		 * for some other reason.  Do not change our opinion about
  1.2266 +		 * the nameserver. */
  1.2267 +		return;
  1.2268 +	}
  1.2269 +
  1.2270 +	EVDNS_LOCK(ns->base);
  1.2271 +	ns->probe_request = NULL;
  1.2272 +	if (result == DNS_ERR_NONE || result == DNS_ERR_NOTEXIST) {
  1.2273 +		/* this is a good reply */
  1.2274 +		nameserver_up(ns);
  1.2275 +	} else {
  1.2276 +		nameserver_probe_failed(ns);
  1.2277 +	}
  1.2278 +	EVDNS_UNLOCK(ns->base);
  1.2279 +}
  1.2280 +
  1.2281 +static void
  1.2282 +nameserver_send_probe(struct nameserver *const ns) {
  1.2283 +	struct evdns_request *handle;
  1.2284 +	struct request *req;
  1.2285 +	char addrbuf[128];
  1.2286 +	/* here we need to send a probe to a given nameserver */
  1.2287 +	/* in the hope that it is up now. */
  1.2288 +
  1.2289 +	ASSERT_LOCKED(ns->base);
  1.2290 +	log(EVDNS_LOG_DEBUG, "Sending probe to %s",
  1.2291 +	    evutil_format_sockaddr_port(
  1.2292 +		    (struct sockaddr *)&ns->address,
  1.2293 +		    addrbuf, sizeof(addrbuf)));
  1.2294 +	handle = mm_calloc(1, sizeof(*handle));
  1.2295 +	if (!handle) return;
  1.2296 +	req = request_new(ns->base, handle, TYPE_A, "google.com", DNS_QUERY_NO_SEARCH, nameserver_probe_callback, ns);
  1.2297 +	if (!req) {
  1.2298 +		mm_free(handle);
  1.2299 +		return;
  1.2300 +	}
  1.2301 +	ns->probe_request = handle;
  1.2302 +	/* we force this into the inflight queue no matter what */
  1.2303 +	request_trans_id_set(req, transaction_id_pick(ns->base));
  1.2304 +	req->ns = ns;
  1.2305 +	request_submit(req);
  1.2306 +}
  1.2307 +
  1.2308 +/* returns: */
  1.2309 +/*   0 didn't try to transmit anything */
  1.2310 +/*   1 tried to transmit something */
  1.2311 +static int
  1.2312 +evdns_transmit(struct evdns_base *base) {
  1.2313 +	char did_try_to_transmit = 0;
  1.2314 +	int i;
  1.2315 +
  1.2316 +	ASSERT_LOCKED(base);
  1.2317 +	for (i = 0; i < base->n_req_heads; ++i) {
  1.2318 +		if (base->req_heads[i]) {
  1.2319 +			struct request *const started_at = base->req_heads[i], *req = started_at;
  1.2320 +			/* first transmit all the requests which are currently waiting */
  1.2321 +			do {
  1.2322 +				if (req->transmit_me) {
  1.2323 +					did_try_to_transmit = 1;
  1.2324 +					evdns_request_transmit(req);
  1.2325 +				}
  1.2326 +
  1.2327 +				req = req->next;
  1.2328 +			} while (req != started_at);
  1.2329 +		}
  1.2330 +	}
  1.2331 +
  1.2332 +	return did_try_to_transmit;
  1.2333 +}
  1.2334 +
  1.2335 +/* exported function */
  1.2336 +int
  1.2337 +evdns_base_count_nameservers(struct evdns_base *base)
  1.2338 +{
  1.2339 +	const struct nameserver *server;
  1.2340 +	int n = 0;
  1.2341 +
  1.2342 +	EVDNS_LOCK(base);
  1.2343 +	server = base->server_head;
  1.2344 +	if (!server)
  1.2345 +		goto done;
  1.2346 +	do {
  1.2347 +		++n;
  1.2348 +		server = server->next;
  1.2349 +	} while (server != base->server_head);
  1.2350 +done:
  1.2351 +	EVDNS_UNLOCK(base);
  1.2352 +	return n;
  1.2353 +}
  1.2354 +
  1.2355 +int
  1.2356 +evdns_count_nameservers(void)
  1.2357 +{
  1.2358 +	return evdns_base_count_nameservers(current_base);
  1.2359 +}
  1.2360 +
  1.2361 +/* exported function */
  1.2362 +int
  1.2363 +evdns_base_clear_nameservers_and_suspend(struct evdns_base *base)
  1.2364 +{
  1.2365 +	struct nameserver *server, *started_at;
  1.2366 +	int i;
  1.2367 +
  1.2368 +	EVDNS_LOCK(base);
  1.2369 +	server = base->server_head;
  1.2370 +	started_at = base->server_head;
  1.2371 +	if (!server) {
  1.2372 +		EVDNS_UNLOCK(base);
  1.2373 +		return 0;
  1.2374 +	}
  1.2375 +	while (1) {
  1.2376 +		struct nameserver *next = server->next;
  1.2377 +		(void) event_del(&server->event);
  1.2378 +		if (evtimer_initialized(&server->timeout_event))
  1.2379 +			(void) evtimer_del(&server->timeout_event);
  1.2380 +		if (server->probe_request) {
  1.2381 +			evdns_cancel_request(server->base, server->probe_request);
  1.2382 +			server->probe_request = NULL;
  1.2383 +		}
  1.2384 +		if (server->socket >= 0)
  1.2385 +			evutil_closesocket(server->socket);
  1.2386 +		mm_free(server);
  1.2387 +		if (next == started_at)
  1.2388 +			break;
  1.2389 +		server = next;
  1.2390 +	}
  1.2391 +	base->server_head = NULL;
  1.2392 +	base->global_good_nameservers = 0;
  1.2393 +
  1.2394 +	for (i = 0; i < base->n_req_heads; ++i) {
  1.2395 +		struct request *req, *req_started_at;
  1.2396 +		req = req_started_at = base->req_heads[i];
  1.2397 +		while (req) {
  1.2398 +			struct request *next = req->next;
  1.2399 +			req->tx_count = req->reissue_count = 0;
  1.2400 +			req->ns = NULL;
  1.2401 +			/* ???? What to do about searches? */
  1.2402 +			(void) evtimer_del(&req->timeout_event);
  1.2403 +			req->trans_id = 0;
  1.2404 +			req->transmit_me = 0;
  1.2405 +
  1.2406 +			base->global_requests_waiting++;
  1.2407 +			evdns_request_insert(req, &base->req_waiting_head);
  1.2408 +			/* We want to insert these suspended elements at the front of
  1.2409 +			 * the waiting queue, since they were pending before any of
  1.2410 +			 * the waiting entries were added.  This is a circular list,
  1.2411 +			 * so we can just shift the start back by one.*/
  1.2412 +			base->req_waiting_head = base->req_waiting_head->prev;
  1.2413 +
  1.2414 +			if (next == req_started_at)
  1.2415 +				break;
  1.2416 +			req = next;
  1.2417 +		}
  1.2418 +		base->req_heads[i] = NULL;
  1.2419 +	}
  1.2420 +
  1.2421 +	base->global_requests_inflight = 0;
  1.2422 +
  1.2423 +	EVDNS_UNLOCK(base);
  1.2424 +	return 0;
  1.2425 +}
  1.2426 +
  1.2427 +int
  1.2428 +evdns_clear_nameservers_and_suspend(void)
  1.2429 +{
  1.2430 +	return evdns_base_clear_nameservers_and_suspend(current_base);
  1.2431 +}
  1.2432 +
  1.2433 +
  1.2434 +/* exported function */
  1.2435 +int
  1.2436 +evdns_base_resume(struct evdns_base *base)
  1.2437 +{
  1.2438 +	EVDNS_LOCK(base);
  1.2439 +	evdns_requests_pump_waiting_queue(base);
  1.2440 +	EVDNS_UNLOCK(base);
  1.2441 +	return 0;
  1.2442 +}
  1.2443 +
  1.2444 +int
  1.2445 +evdns_resume(void)
  1.2446 +{
  1.2447 +	return evdns_base_resume(current_base);
  1.2448 +}
  1.2449 +
  1.2450 +static int
  1.2451 +_evdns_nameserver_add_impl(struct evdns_base *base, const struct sockaddr *address, int addrlen) {
  1.2452 +	/* first check to see if we already have this nameserver */
  1.2453 +
  1.2454 +	const struct nameserver *server = base->server_head, *const started_at = base->server_head;
  1.2455 +	struct nameserver *ns;
  1.2456 +	int err = 0;
  1.2457 +	char addrbuf[128];
  1.2458 +
  1.2459 +	ASSERT_LOCKED(base);
  1.2460 +	if (server) {
  1.2461 +		do {
  1.2462 +			if (!evutil_sockaddr_cmp((struct sockaddr*)&server->address, address, 1)) return 3;
  1.2463 +			server = server->next;
  1.2464 +		} while (server != started_at);
  1.2465 +	}
  1.2466 +	if (addrlen > (int)sizeof(ns->address)) {
  1.2467 +		log(EVDNS_LOG_DEBUG, "Addrlen %d too long.", (int)addrlen);
  1.2468 +		return 2;
  1.2469 +	}
  1.2470 +
  1.2471 +	ns = (struct nameserver *) mm_malloc(sizeof(struct nameserver));
  1.2472 +	if (!ns) return -1;
  1.2473 +
  1.2474 +	memset(ns, 0, sizeof(struct nameserver));
  1.2475 +	ns->base = base;
  1.2476 +
  1.2477 +	evtimer_assign(&ns->timeout_event, ns->base->event_base, nameserver_prod_callback, ns);
  1.2478 +
  1.2479 +	ns->socket = socket(address->sa_family, SOCK_DGRAM, 0);
  1.2480 +	if (ns->socket < 0) { err = 1; goto out1; }
  1.2481 +	evutil_make_socket_closeonexec(ns->socket);
  1.2482 +	evutil_make_socket_nonblocking(ns->socket);
  1.2483 +
  1.2484 +	if (base->global_outgoing_addrlen &&
  1.2485 +	    !evutil_sockaddr_is_loopback(address)) {
  1.2486 +		if (bind(ns->socket,
  1.2487 +			(struct sockaddr*)&base->global_outgoing_address,
  1.2488 +			base->global_outgoing_addrlen) < 0) {
  1.2489 +			log(EVDNS_LOG_WARN,"Couldn't bind to outgoing address");
  1.2490 +			err = 2;
  1.2491 +			goto out2;
  1.2492 +		}
  1.2493 +	}
  1.2494 +
  1.2495 +	memcpy(&ns->address, address, addrlen);
  1.2496 +	ns->addrlen = addrlen;
  1.2497 +	ns->state = 1;
  1.2498 +	event_assign(&ns->event, ns->base->event_base, ns->socket, EV_READ | EV_PERSIST, nameserver_ready_callback, ns);
  1.2499 +	if (event_add(&ns->event, NULL) < 0) {
  1.2500 +		err = 2;
  1.2501 +		goto out2;
  1.2502 +	}
  1.2503 +
  1.2504 +	log(EVDNS_LOG_DEBUG, "Added nameserver %s as %p",
  1.2505 +	    evutil_format_sockaddr_port(address, addrbuf, sizeof(addrbuf)), ns);
  1.2506 +
  1.2507 +	/* insert this nameserver into the list of them */
  1.2508 +	if (!base->server_head) {
  1.2509 +		ns->next = ns->prev = ns;
  1.2510 +		base->server_head = ns;
  1.2511 +	} else {
  1.2512 +		ns->next = base->server_head->next;
  1.2513 +		ns->prev = base->server_head;
  1.2514 +		base->server_head->next = ns;
  1.2515 +		ns->next->prev = ns;
  1.2516 +	}
  1.2517 +
  1.2518 +	base->global_good_nameservers++;
  1.2519 +
  1.2520 +	return 0;
  1.2521 +
  1.2522 +out2:
  1.2523 +	evutil_closesocket(ns->socket);
  1.2524 +out1:
  1.2525 +	event_debug_unassign(&ns->event);
  1.2526 +	mm_free(ns);
  1.2527 +	log(EVDNS_LOG_WARN, "Unable to add nameserver %s: error %d",
  1.2528 +	    evutil_format_sockaddr_port(address, addrbuf, sizeof(addrbuf)), err);
  1.2529 +	return err;
  1.2530 +}
  1.2531 +
  1.2532 +/* exported function */
  1.2533 +int
  1.2534 +evdns_base_nameserver_add(struct evdns_base *base, unsigned long int address)
  1.2535 +{
  1.2536 +	struct sockaddr_in sin;
  1.2537 +	int res;
  1.2538 +	memset(&sin, 0, sizeof(sin));
  1.2539 +	sin.sin_addr.s_addr = address;
  1.2540 +	sin.sin_port = htons(53);
  1.2541 +	sin.sin_family = AF_INET;
  1.2542 +	EVDNS_LOCK(base);
  1.2543 +	res = _evdns_nameserver_add_impl(base, (struct sockaddr*)&sin, sizeof(sin));
  1.2544 +	EVDNS_UNLOCK(base);
  1.2545 +	return res;
  1.2546 +}
  1.2547 +
  1.2548 +int
  1.2549 +evdns_nameserver_add(unsigned long int address) {
  1.2550 +	if (!current_base)
  1.2551 +		current_base = evdns_base_new(NULL, 0);
  1.2552 +	return evdns_base_nameserver_add(current_base, address);
  1.2553 +}
  1.2554 +
  1.2555 +static void
  1.2556 +sockaddr_setport(struct sockaddr *sa, ev_uint16_t port)
  1.2557 +{
  1.2558 +	if (sa->sa_family == AF_INET) {
  1.2559 +		((struct sockaddr_in *)sa)->sin_port = htons(port);
  1.2560 +	} else if (sa->sa_family == AF_INET6) {
  1.2561 +		((struct sockaddr_in6 *)sa)->sin6_port = htons(port);
  1.2562 +	}
  1.2563 +}
  1.2564 +
  1.2565 +static ev_uint16_t
  1.2566 +sockaddr_getport(struct sockaddr *sa)
  1.2567 +{
  1.2568 +	if (sa->sa_family == AF_INET) {
  1.2569 +		return ntohs(((struct sockaddr_in *)sa)->sin_port);
  1.2570 +	} else if (sa->sa_family == AF_INET6) {
  1.2571 +		return ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
  1.2572 +	} else {
  1.2573 +		return 0;
  1.2574 +	}
  1.2575 +}
  1.2576 +
  1.2577 +/* exported function */
  1.2578 +int
  1.2579 +evdns_base_nameserver_ip_add(struct evdns_base *base, const char *ip_as_string) {
  1.2580 +	struct sockaddr_storage ss;
  1.2581 +	struct sockaddr *sa;
  1.2582 +	int len = sizeof(ss);
  1.2583 +	int res;
  1.2584 +	if (evutil_parse_sockaddr_port(ip_as_string, (struct sockaddr *)&ss,
  1.2585 +		&len)) {
  1.2586 +		log(EVDNS_LOG_WARN, "Unable to parse nameserver address %s",
  1.2587 +			ip_as_string);
  1.2588 +		return 4;
  1.2589 +	}
  1.2590 +	sa = (struct sockaddr *) &ss;
  1.2591 +	if (sockaddr_getport(sa) == 0)
  1.2592 +		sockaddr_setport(sa, 53);
  1.2593 +
  1.2594 +	EVDNS_LOCK(base);
  1.2595 +	res = _evdns_nameserver_add_impl(base, sa, len);
  1.2596 +	EVDNS_UNLOCK(base);
  1.2597 +	return res;
  1.2598 +}
  1.2599 +
  1.2600 +int
  1.2601 +evdns_nameserver_ip_add(const char *ip_as_string) {
  1.2602 +	if (!current_base)
  1.2603 +		current_base = evdns_base_new(NULL, 0);
  1.2604 +	return evdns_base_nameserver_ip_add(current_base, ip_as_string);
  1.2605 +}
  1.2606 +
  1.2607 +int
  1.2608 +evdns_base_nameserver_sockaddr_add(struct evdns_base *base,
  1.2609 +    const struct sockaddr *sa, ev_socklen_t len, unsigned flags)
  1.2610 +{
  1.2611 +	int res;
  1.2612 +	EVUTIL_ASSERT(base);
  1.2613 +	EVDNS_LOCK(base);
  1.2614 +	res = _evdns_nameserver_add_impl(base, sa, len);
  1.2615 +	EVDNS_UNLOCK(base);
  1.2616 +	return res;
  1.2617 +}
  1.2618 +
  1.2619 +/* remove from the queue */
  1.2620 +static void
  1.2621 +evdns_request_remove(struct request *req, struct request **head)
  1.2622 +{
  1.2623 +	ASSERT_LOCKED(req->base);
  1.2624 +	ASSERT_VALID_REQUEST(req);
  1.2625 +
  1.2626 +#if 0
  1.2627 +	{
  1.2628 +		struct request *ptr;
  1.2629 +		int found = 0;
  1.2630 +		EVUTIL_ASSERT(*head != NULL);
  1.2631 +
  1.2632 +		ptr = *head;
  1.2633 +		do {
  1.2634 +			if (ptr == req) {
  1.2635 +				found = 1;
  1.2636 +				break;
  1.2637 +			}
  1.2638 +			ptr = ptr->next;
  1.2639 +		} while (ptr != *head);
  1.2640 +		EVUTIL_ASSERT(found);
  1.2641 +
  1.2642 +		EVUTIL_ASSERT(req->next);
  1.2643 +	}
  1.2644 +#endif
  1.2645 +
  1.2646 +	if (req->next == req) {
  1.2647 +		/* only item in the list */
  1.2648 +		*head = NULL;
  1.2649 +	} else {
  1.2650 +		req->next->prev = req->prev;
  1.2651 +		req->prev->next = req->next;
  1.2652 +		if (*head == req) *head = req->next;
  1.2653 +	}
  1.2654 +	req->next = req->prev = NULL;
  1.2655 +}
  1.2656 +
  1.2657 +/* insert into the tail of the queue */
  1.2658 +static void
  1.2659 +evdns_request_insert(struct request *req, struct request **head) {
  1.2660 +	ASSERT_LOCKED(req->base);
  1.2661 +	ASSERT_VALID_REQUEST(req);
  1.2662 +	if (!*head) {
  1.2663 +		*head = req;
  1.2664 +		req->next = req->prev = req;
  1.2665 +		return;
  1.2666 +	}
  1.2667 +
  1.2668 +	req->prev = (*head)->prev;
  1.2669 +	req->prev->next = req;
  1.2670 +	req->next = *head;
  1.2671 +	(*head)->prev = req;
  1.2672 +}
  1.2673 +
  1.2674 +static int
  1.2675 +string_num_dots(const char *s) {
  1.2676 +	int count = 0;
  1.2677 +	while ((s = strchr(s, '.'))) {
  1.2678 +		s++;
  1.2679 +		count++;
  1.2680 +	}
  1.2681 +	return count;
  1.2682 +}
  1.2683 +
  1.2684 +static struct request *
  1.2685 +request_new(struct evdns_base *base, struct evdns_request *handle, int type,
  1.2686 +	    const char *name, int flags, evdns_callback_type callback,
  1.2687 +	    void *user_ptr) {
  1.2688 +
  1.2689 +	const char issuing_now =
  1.2690 +	    (base->global_requests_inflight < base->global_max_requests_inflight) ? 1 : 0;
  1.2691 +
  1.2692 +	const size_t name_len = strlen(name);
  1.2693 +	const size_t request_max_len = evdns_request_len(name_len);
  1.2694 +	const u16 trans_id = issuing_now ? transaction_id_pick(base) : 0xffff;
  1.2695 +	/* the request data is alloced in a single block with the header */
  1.2696 +	struct request *const req =
  1.2697 +	    mm_malloc(sizeof(struct request) + request_max_len);
  1.2698 +	int rlen;
  1.2699 +	char namebuf[256];
  1.2700 +	(void) flags;
  1.2701 +
  1.2702 +	ASSERT_LOCKED(base);
  1.2703 +
  1.2704 +	if (!req) return NULL;
  1.2705 +
  1.2706 +	if (name_len >= sizeof(namebuf)) {
  1.2707 +		mm_free(req);
  1.2708 +		return NULL;
  1.2709 +	}
  1.2710 +
  1.2711 +	memset(req, 0, sizeof(struct request));
  1.2712 +	req->base = base;
  1.2713 +
  1.2714 +	evtimer_assign(&req->timeout_event, req->base->event_base, evdns_request_timeout_callback, req);
  1.2715 +
  1.2716 +	if (base->global_randomize_case) {
  1.2717 +		unsigned i;
  1.2718 +		char randbits[(sizeof(namebuf)+7)/8];
  1.2719 +		strlcpy(namebuf, name, sizeof(namebuf));
  1.2720 +		evutil_secure_rng_get_bytes(randbits, (name_len+7)/8);
  1.2721 +		for (i = 0; i < name_len; ++i) {
  1.2722 +			if (EVUTIL_ISALPHA(namebuf[i])) {
  1.2723 +				if ((randbits[i >> 3] & (1<<(i & 7))))
  1.2724 +					namebuf[i] |= 0x20;
  1.2725 +				else
  1.2726 +					namebuf[i] &= ~0x20;
  1.2727 +			}
  1.2728 +		}
  1.2729 +		name = namebuf;
  1.2730 +	}
  1.2731 +
  1.2732 +	/* request data lives just after the header */
  1.2733 +	req->request = ((u8 *) req) + sizeof(struct request);
  1.2734 +	/* denotes that the request data shouldn't be free()ed */
  1.2735 +	req->request_appended = 1;
  1.2736 +	rlen = evdns_request_data_build(name, name_len, trans_id,
  1.2737 +	    type, CLASS_INET, req->request, request_max_len);
  1.2738 +	if (rlen < 0)
  1.2739 +		goto err1;
  1.2740 +
  1.2741 +	req->request_len = rlen;
  1.2742 +	req->trans_id = trans_id;
  1.2743 +	req->tx_count = 0;
  1.2744 +	req->request_type = type;
  1.2745 +	req->user_pointer = user_ptr;
  1.2746 +	req->user_callback = callback;
  1.2747 +	req->ns = issuing_now ? nameserver_pick(base) : NULL;
  1.2748 +	req->next = req->prev = NULL;
  1.2749 +	req->handle = handle;
  1.2750 +	if (handle) {
  1.2751 +		handle->current_req = req;
  1.2752 +		handle->base = base;
  1.2753 +	}
  1.2754 +
  1.2755 +	return req;
  1.2756 +err1:
  1.2757 +	mm_free(req);
  1.2758 +	return NULL;
  1.2759 +}
  1.2760 +
  1.2761 +static void
  1.2762 +request_submit(struct request *const req) {
  1.2763 +	struct evdns_base *base = req->base;
  1.2764 +	ASSERT_LOCKED(base);
  1.2765 +	ASSERT_VALID_REQUEST(req);
  1.2766 +	if (req->ns) {
  1.2767 +		/* if it has a nameserver assigned then this is going */
  1.2768 +		/* straight into the inflight queue */
  1.2769 +		evdns_request_insert(req, &REQ_HEAD(base, req->trans_id));
  1.2770 +		base->global_requests_inflight++;
  1.2771 +		evdns_request_transmit(req);
  1.2772 +	} else {
  1.2773 +		evdns_request_insert(req, &base->req_waiting_head);
  1.2774 +		base->global_requests_waiting++;
  1.2775 +	}
  1.2776 +}
  1.2777 +
  1.2778 +/* exported function */
  1.2779 +void
  1.2780 +evdns_cancel_request(struct evdns_base *base, struct evdns_request *handle)
  1.2781 +{
  1.2782 +	struct request *req;
  1.2783 +
  1.2784 +	if (!handle->current_req)
  1.2785 +		return;
  1.2786 +
  1.2787 +	if (!base) {
  1.2788 +		/* This redundancy is silly; can we fix it? (Not for 2.0) XXXX */
  1.2789 +		base = handle->base;
  1.2790 +		if (!base)
  1.2791 +			base = handle->current_req->base;
  1.2792 +	}
  1.2793 +
  1.2794 +	EVDNS_LOCK(base);
  1.2795 +	if (handle->pending_cb) {
  1.2796 +		EVDNS_UNLOCK(base);
  1.2797 +		return;
  1.2798 +	}
  1.2799 +
  1.2800 +	req = handle->current_req;
  1.2801 +	ASSERT_VALID_REQUEST(req);
  1.2802 +
  1.2803 +	reply_schedule_callback(req, 0, DNS_ERR_CANCEL, NULL);
  1.2804 +	if (req->ns) {
  1.2805 +		/* remove from inflight queue */
  1.2806 +		request_finished(req, &REQ_HEAD(base, req->trans_id), 1);
  1.2807 +	} else {
  1.2808 +		/* remove from global_waiting head */
  1.2809 +		request_finished(req, &base->req_waiting_head, 1);
  1.2810 +	}
  1.2811 +	EVDNS_UNLOCK(base);
  1.2812 +}
  1.2813 +
  1.2814 +/* exported function */
  1.2815 +struct evdns_request *
  1.2816 +evdns_base_resolve_ipv4(struct evdns_base *base, const char *name, int flags,
  1.2817 +    evdns_callback_type callback, void *ptr) {
  1.2818 +	struct evdns_request *handle;
  1.2819 +	struct request *req;
  1.2820 +	log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
  1.2821 +	handle = mm_calloc(1, sizeof(*handle));
  1.2822 +	if (handle == NULL)
  1.2823 +		return NULL;
  1.2824 +	EVDNS_LOCK(base);
  1.2825 +	if (flags & DNS_QUERY_NO_SEARCH) {
  1.2826 +		req =
  1.2827 +			request_new(base, handle, TYPE_A, name, flags,
  1.2828 +				    callback, ptr);
  1.2829 +		if (req)
  1.2830 +			request_submit(req);
  1.2831 +	} else {
  1.2832 +		search_request_new(base, handle, TYPE_A, name, flags,
  1.2833 +		    callback, ptr);
  1.2834 +	}
  1.2835 +	if (handle->current_req == NULL) {
  1.2836 +		mm_free(handle);
  1.2837 +		handle = NULL;
  1.2838 +	}
  1.2839 +	EVDNS_UNLOCK(base);
  1.2840 +	return handle;
  1.2841 +}
  1.2842 +
  1.2843 +int evdns_resolve_ipv4(const char *name, int flags,
  1.2844 +					   evdns_callback_type callback, void *ptr)
  1.2845 +{
  1.2846 +	return evdns_base_resolve_ipv4(current_base, name, flags, callback, ptr)
  1.2847 +		? 0 : -1;
  1.2848 +}
  1.2849 +
  1.2850 +
  1.2851 +/* exported function */
  1.2852 +struct evdns_request *
  1.2853 +evdns_base_resolve_ipv6(struct evdns_base *base,
  1.2854 +    const char *name, int flags,
  1.2855 +    evdns_callback_type callback, void *ptr)
  1.2856 +{
  1.2857 +	struct evdns_request *handle;
  1.2858 +	struct request *req;
  1.2859 +	log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
  1.2860 +	handle = mm_calloc(1, sizeof(*handle));
  1.2861 +	if (handle == NULL)
  1.2862 +		return NULL;
  1.2863 +	EVDNS_LOCK(base);
  1.2864 +	if (flags & DNS_QUERY_NO_SEARCH) {
  1.2865 +		req = request_new(base, handle, TYPE_AAAA, name, flags,
  1.2866 +				  callback, ptr);
  1.2867 +		if (req)
  1.2868 +			request_submit(req);
  1.2869 +	} else {
  1.2870 +		search_request_new(base, handle, TYPE_AAAA, name, flags,
  1.2871 +		    callback, ptr);
  1.2872 +	}
  1.2873 +	if (handle->current_req == NULL) {
  1.2874 +		mm_free(handle);
  1.2875 +		handle = NULL;
  1.2876 +	}
  1.2877 +	EVDNS_UNLOCK(base);
  1.2878 +	return handle;
  1.2879 +}
  1.2880 +
  1.2881 +int evdns_resolve_ipv6(const char *name, int flags,
  1.2882 +    evdns_callback_type callback, void *ptr) {
  1.2883 +	return evdns_base_resolve_ipv6(current_base, name, flags, callback, ptr)
  1.2884 +		? 0 : -1;
  1.2885 +}
  1.2886 +
  1.2887 +struct evdns_request *
  1.2888 +evdns_base_resolve_reverse(struct evdns_base *base, const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) {
  1.2889 +	char buf[32];
  1.2890 +	struct evdns_request *handle;
  1.2891 +	struct request *req;
  1.2892 +	u32 a;
  1.2893 +	EVUTIL_ASSERT(in);
  1.2894 +	a = ntohl(in->s_addr);
  1.2895 +	evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
  1.2896 +			(int)(u8)((a	)&0xff),
  1.2897 +			(int)(u8)((a>>8 )&0xff),
  1.2898 +			(int)(u8)((a>>16)&0xff),
  1.2899 +			(int)(u8)((a>>24)&0xff));
  1.2900 +	handle = mm_calloc(1, sizeof(*handle));
  1.2901 +	if (handle == NULL)
  1.2902 +		return NULL;
  1.2903 +	log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
  1.2904 +	EVDNS_LOCK(base);
  1.2905 +	req = request_new(base, handle, TYPE_PTR, buf, flags, callback, ptr);
  1.2906 +	if (req)
  1.2907 +		request_submit(req);
  1.2908 +	if (handle->current_req == NULL) {
  1.2909 +		mm_free(handle);
  1.2910 +		handle = NULL;
  1.2911 +	}
  1.2912 +	EVDNS_UNLOCK(base);
  1.2913 +	return (handle);
  1.2914 +}
  1.2915 +
  1.2916 +int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) {
  1.2917 +	return evdns_base_resolve_reverse(current_base, in, flags, callback, ptr)
  1.2918 +		? 0 : -1;
  1.2919 +}
  1.2920 +
  1.2921 +struct evdns_request *
  1.2922 +evdns_base_resolve_reverse_ipv6(struct evdns_base *base, const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) {
  1.2923 +	/* 32 nybbles, 32 periods, "ip6.arpa", NUL. */
  1.2924 +	char buf[73];
  1.2925 +	char *cp;
  1.2926 +	struct evdns_request *handle;
  1.2927 +	struct request *req;
  1.2928 +	int i;
  1.2929 +	EVUTIL_ASSERT(in);
  1.2930 +	cp = buf;
  1.2931 +	for (i=15; i >= 0; --i) {
  1.2932 +		u8 byte = in->s6_addr[i];
  1.2933 +		*cp++ = "0123456789abcdef"[byte & 0x0f];
  1.2934 +		*cp++ = '.';
  1.2935 +		*cp++ = "0123456789abcdef"[byte >> 4];
  1.2936 +		*cp++ = '.';
  1.2937 +	}
  1.2938 +	EVUTIL_ASSERT(cp + strlen("ip6.arpa") < buf+sizeof(buf));
  1.2939 +	memcpy(cp, "ip6.arpa", strlen("ip6.arpa")+1);
  1.2940 +	handle = mm_calloc(1, sizeof(*handle));
  1.2941 +	if (handle == NULL)
  1.2942 +		return NULL;
  1.2943 +	log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
  1.2944 +	EVDNS_LOCK(base);
  1.2945 +	req = request_new(base, handle, TYPE_PTR, buf, flags, callback, ptr);
  1.2946 +	if (req)
  1.2947 +		request_submit(req);
  1.2948 +	if (handle->current_req == NULL) {
  1.2949 +		mm_free(handle);
  1.2950 +		handle = NULL;
  1.2951 +	}
  1.2952 +	EVDNS_UNLOCK(base);
  1.2953 +	return (handle);
  1.2954 +}
  1.2955 +
  1.2956 +int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) {
  1.2957 +	return evdns_base_resolve_reverse_ipv6(current_base, in, flags, callback, ptr)
  1.2958 +		? 0 : -1;
  1.2959 +}
  1.2960 +
  1.2961 +/* ================================================================= */
  1.2962 +/* Search support */
  1.2963 +/* */
  1.2964 +/* the libc resolver has support for searching a number of domains */
  1.2965 +/* to find a name. If nothing else then it takes the single domain */
  1.2966 +/* from the gethostname() call. */
  1.2967 +/* */
  1.2968 +/* It can also be configured via the domain and search options in a */
  1.2969 +/* resolv.conf. */
  1.2970 +/* */
  1.2971 +/* The ndots option controls how many dots it takes for the resolver */
  1.2972 +/* to decide that a name is non-local and so try a raw lookup first. */
  1.2973 +
  1.2974 +struct search_domain {
  1.2975 +	int len;
  1.2976 +	struct search_domain *next;
  1.2977 +	/* the text string is appended to this structure */
  1.2978 +};
  1.2979 +
  1.2980 +struct search_state {
  1.2981 +	int refcount;
  1.2982 +	int ndots;
  1.2983 +	int num_domains;
  1.2984 +	struct search_domain *head;
  1.2985 +};
  1.2986 +
  1.2987 +static void
  1.2988 +search_state_decref(struct search_state *const state) {
  1.2989 +	if (!state) return;
  1.2990 +	state->refcount--;
  1.2991 +	if (!state->refcount) {
  1.2992 +		struct search_domain *next, *dom;
  1.2993 +		for (dom = state->head; dom; dom = next) {
  1.2994 +			next = dom->next;
  1.2995 +			mm_free(dom);
  1.2996 +		}
  1.2997 +		mm_free(state);
  1.2998 +	}
  1.2999 +}
  1.3000 +
  1.3001 +static struct search_state *
  1.3002 +search_state_new(void) {
  1.3003 +	struct search_state *state = (struct search_state *) mm_malloc(sizeof(struct search_state));
  1.3004 +	if (!state) return NULL;
  1.3005 +	memset(state, 0, sizeof(struct search_state));
  1.3006 +	state->refcount = 1;
  1.3007 +	state->ndots = 1;
  1.3008 +
  1.3009 +	return state;
  1.3010 +}
  1.3011 +
  1.3012 +static void
  1.3013 +search_postfix_clear(struct evdns_base *base) {
  1.3014 +	search_state_decref(base->global_search_state);
  1.3015 +
  1.3016 +	base->global_search_state = search_state_new();
  1.3017 +}
  1.3018 +
  1.3019 +/* exported function */
  1.3020 +void
  1.3021 +evdns_base_search_clear(struct evdns_base *base)
  1.3022 +{
  1.3023 +	EVDNS_LOCK(base);
  1.3024 +	search_postfix_clear(base);
  1.3025 +	EVDNS_UNLOCK(base);
  1.3026 +}
  1.3027 +
  1.3028 +void
  1.3029 +evdns_search_clear(void) {
  1.3030 +	evdns_base_search_clear(current_base);
  1.3031 +}
  1.3032 +
  1.3033 +static void
  1.3034 +search_postfix_add(struct evdns_base *base, const char *domain) {
  1.3035 +	size_t domain_len;
  1.3036 +	struct search_domain *sdomain;
  1.3037 +	while (domain[0] == '.') domain++;
  1.3038 +	domain_len = strlen(domain);
  1.3039 +
  1.3040 +	ASSERT_LOCKED(base);
  1.3041 +	if (!base->global_search_state) base->global_search_state = search_state_new();
  1.3042 +	if (!base->global_search_state) return;
  1.3043 +	base->global_search_state->num_domains++;
  1.3044 +
  1.3045 +	sdomain = (struct search_domain *) mm_malloc(sizeof(struct search_domain) + domain_len);
  1.3046 +	if (!sdomain) return;
  1.3047 +	memcpy( ((u8 *) sdomain) + sizeof(struct search_domain), domain, domain_len);
  1.3048 +	sdomain->next = base->global_search_state->head;
  1.3049 +	sdomain->len = (int) domain_len;
  1.3050 +
  1.3051 +	base->global_search_state->head = sdomain;
  1.3052 +}
  1.3053 +
  1.3054 +/* reverse the order of members in the postfix list. This is needed because, */
  1.3055 +/* when parsing resolv.conf we push elements in the wrong order */
  1.3056 +static void
  1.3057 +search_reverse(struct evdns_base *base) {
  1.3058 +	struct search_domain *cur, *prev = NULL, *next;
  1.3059 +	ASSERT_LOCKED(base);
  1.3060 +	cur = base->global_search_state->head;
  1.3061 +	while (cur) {
  1.3062 +		next = cur->next;
  1.3063 +		cur->next = prev;
  1.3064 +		prev = cur;
  1.3065 +		cur = next;
  1.3066 +	}
  1.3067 +
  1.3068 +	base->global_search_state->head = prev;
  1.3069 +}
  1.3070 +
  1.3071 +/* exported function */
  1.3072 +void
  1.3073 +evdns_base_search_add(struct evdns_base *base, const char *domain) {
  1.3074 +	EVDNS_LOCK(base);
  1.3075 +	search_postfix_add(base, domain);
  1.3076 +	EVDNS_UNLOCK(base);
  1.3077 +}
  1.3078 +void
  1.3079 +evdns_search_add(const char *domain) {
  1.3080 +	evdns_base_search_add(current_base, domain);
  1.3081 +}
  1.3082 +
  1.3083 +/* exported function */
  1.3084 +void
  1.3085 +evdns_base_search_ndots_set(struct evdns_base *base, const int ndots) {
  1.3086 +	EVDNS_LOCK(base);
  1.3087 +	if (!base->global_search_state) base->global_search_state = search_state_new();
  1.3088 +	if (base->global_search_state)
  1.3089 +		base->global_search_state->ndots = ndots;
  1.3090 +	EVDNS_UNLOCK(base);
  1.3091 +}
  1.3092 +void
  1.3093 +evdns_search_ndots_set(const int ndots) {
  1.3094 +	evdns_base_search_ndots_set(current_base, ndots);
  1.3095 +}
  1.3096 +
  1.3097 +static void
  1.3098 +search_set_from_hostname(struct evdns_base *base) {
  1.3099 +	char hostname[HOST_NAME_MAX + 1], *domainname;
  1.3100 +
  1.3101 +	ASSERT_LOCKED(base);
  1.3102 +	search_postfix_clear(base);
  1.3103 +	if (gethostname(hostname, sizeof(hostname))) return;
  1.3104 +	domainname = strchr(hostname, '.');
  1.3105 +	if (!domainname) return;
  1.3106 +	search_postfix_add(base, domainname);
  1.3107 +}
  1.3108 +
  1.3109 +/* warning: returns malloced string */
  1.3110 +static char *
  1.3111 +search_make_new(const struct search_state *const state, int n, const char *const base_name) {
  1.3112 +	const size_t base_len = strlen(base_name);
  1.3113 +	const char need_to_append_dot = base_name[base_len - 1] == '.' ? 0 : 1;
  1.3114 +	struct search_domain *dom;
  1.3115 +
  1.3116 +	for (dom = state->head; dom; dom = dom->next) {
  1.3117 +		if (!n--) {
  1.3118 +			/* this is the postfix we want */
  1.3119 +			/* the actual postfix string is kept at the end of the structure */
  1.3120 +			const u8 *const postfix = ((u8 *) dom) + sizeof(struct search_domain);
  1.3121 +			const int postfix_len = dom->len;
  1.3122 +			char *const newname = (char *) mm_malloc(base_len + need_to_append_dot + postfix_len + 1);
  1.3123 +			if (!newname) return NULL;
  1.3124 +			memcpy(newname, base_name, base_len);
  1.3125 +			if (need_to_append_dot) newname[base_len] = '.';
  1.3126 +			memcpy(newname + base_len + need_to_append_dot, postfix, postfix_len);
  1.3127 +			newname[base_len + need_to_append_dot + postfix_len] = 0;
  1.3128 +			return newname;
  1.3129 +		}
  1.3130 +	}
  1.3131 +
  1.3132 +	/* we ran off the end of the list and still didn't find the requested string */
  1.3133 +	EVUTIL_ASSERT(0);
  1.3134 +	return NULL; /* unreachable; stops warnings in some compilers. */
  1.3135 +}
  1.3136 +
  1.3137 +static struct request *
  1.3138 +search_request_new(struct evdns_base *base, struct evdns_request *handle,
  1.3139 +		   int type, const char *const name, int flags,
  1.3140 +		   evdns_callback_type user_callback, void *user_arg) {
  1.3141 +	ASSERT_LOCKED(base);
  1.3142 +	EVUTIL_ASSERT(type == TYPE_A || type == TYPE_AAAA);
  1.3143 +	EVUTIL_ASSERT(handle->current_req == NULL);
  1.3144 +	if ( ((flags & DNS_QUERY_NO_SEARCH) == 0) &&
  1.3145 +	     base->global_search_state &&
  1.3146 +		 base->global_search_state->num_domains) {
  1.3147 +		/* we have some domains to search */
  1.3148 +		struct request *req;
  1.3149 +		if (string_num_dots(name) >= base->global_search_state->ndots) {
  1.3150 +			req = request_new(base, handle, type, name, flags, user_callback, user_arg);
  1.3151 +			if (!req) return NULL;
  1.3152 +			handle->search_index = -1;
  1.3153 +		} else {
  1.3154 +			char *const new_name = search_make_new(base->global_search_state, 0, name);
  1.3155 +			if (!new_name) return NULL;
  1.3156 +			req = request_new(base, handle, type, new_name, flags, user_callback, user_arg);
  1.3157 +			mm_free(new_name);
  1.3158 +			if (!req) return NULL;
  1.3159 +			handle->search_index = 0;
  1.3160 +		}
  1.3161 +		EVUTIL_ASSERT(handle->search_origname == NULL);
  1.3162 +		handle->search_origname = mm_strdup(name);
  1.3163 +		if (handle->search_origname == NULL) {
  1.3164 +			/* XXX Should we dealloc req? If yes, how? */
  1.3165 +			if (req)
  1.3166 +				mm_free(req);
  1.3167 +			return NULL;
  1.3168 +		}
  1.3169 +		handle->search_state = base->global_search_state;
  1.3170 +		handle->search_flags = flags;
  1.3171 +		base->global_search_state->refcount++;
  1.3172 +		request_submit(req);
  1.3173 +		return req;
  1.3174 +	} else {
  1.3175 +		struct request *const req = request_new(base, handle, type, name, flags, user_callback, user_arg);
  1.3176 +		if (!req) return NULL;
  1.3177 +		request_submit(req);
  1.3178 +		return req;
  1.3179 +	}
  1.3180 +}
  1.3181 +
  1.3182 +/* this is called when a request has failed to find a name. We need to check */
  1.3183 +/* if it is part of a search and, if so, try the next name in the list */
  1.3184 +/* returns: */
  1.3185 +/*   0 another request has been submitted */
  1.3186 +/*   1 no more requests needed */
  1.3187 +static int
  1.3188 +search_try_next(struct evdns_request *const handle) {
  1.3189 +	struct request *req = handle->current_req;
  1.3190 +	struct evdns_base *base = req->base;
  1.3191 +	struct request *newreq;
  1.3192 +	ASSERT_LOCKED(base);
  1.3193 +	if (handle->search_state) {
  1.3194 +		/* it is part of a search */
  1.3195 +		char *new_name;
  1.3196 +		handle->search_index++;
  1.3197 +		if (handle->search_index >= handle->search_state->num_domains) {
  1.3198 +			/* no more postfixes to try, however we may need to try */
  1.3199 +			/* this name without a postfix */
  1.3200 +			if (string_num_dots(handle->search_origname) < handle->search_state->ndots) {
  1.3201 +				/* yep, we need to try it raw */
  1.3202 +				newreq = request_new(base, NULL, req->request_type, handle->search_origname, handle->search_flags, req->user_callback, req->user_pointer);
  1.3203 +				log(EVDNS_LOG_DEBUG, "Search: trying raw query %s", handle->search_origname);
  1.3204 +				if (newreq) {
  1.3205 +					search_request_finished(handle);
  1.3206 +					goto submit_next;
  1.3207 +				}
  1.3208 +			}
  1.3209 +			return 1;
  1.3210 +		}
  1.3211 +
  1.3212 +		new_name = search_make_new(handle->search_state, handle->search_index, handle->search_origname);
  1.3213 +		if (!new_name) return 1;
  1.3214 +		log(EVDNS_LOG_DEBUG, "Search: now trying %s (%d)", new_name, handle->search_index);
  1.3215 +		newreq = request_new(base, NULL, req->request_type, new_name, handle->search_flags, req->user_callback, req->user_pointer);
  1.3216 +		mm_free(new_name);
  1.3217 +		if (!newreq) return 1;
  1.3218 +		goto submit_next;
  1.3219 +	}
  1.3220 +	return 1;
  1.3221 +
  1.3222 +submit_next:
  1.3223 +	request_finished(req, &REQ_HEAD(req->base, req->trans_id), 0);
  1.3224 +	handle->current_req = newreq;
  1.3225 +	newreq->handle = handle;
  1.3226 +	request_submit(newreq);
  1.3227 +	return 0;
  1.3228 +}
  1.3229 +
  1.3230 +static void
  1.3231 +search_request_finished(struct evdns_request *const handle) {
  1.3232 +	ASSERT_LOCKED(handle->current_req->base);
  1.3233 +	if (handle->search_state) {
  1.3234 +		search_state_decref(handle->search_state);
  1.3235 +		handle->search_state = NULL;
  1.3236 +	}
  1.3237 +	if (handle->search_origname) {
  1.3238 +		mm_free(handle->search_origname);
  1.3239 +		handle->search_origname = NULL;
  1.3240 +	}
  1.3241 +}
  1.3242 +
  1.3243 +/* ================================================================= */
  1.3244 +/* Parsing resolv.conf files */
  1.3245 +
  1.3246 +static void
  1.3247 +evdns_resolv_set_defaults(struct evdns_base *base, int flags) {
  1.3248 +	/* if the file isn't found then we assume a local resolver */
  1.3249 +	ASSERT_LOCKED(base);
  1.3250 +	if (flags & DNS_OPTION_SEARCH) search_set_from_hostname(base);
  1.3251 +	if (flags & DNS_OPTION_NAMESERVERS) evdns_base_nameserver_ip_add(base,"127.0.0.1");
  1.3252 +}
  1.3253 +
  1.3254 +#ifndef _EVENT_HAVE_STRTOK_R
  1.3255 +static char *
  1.3256 +strtok_r(char *s, const char *delim, char **state) {
  1.3257 +	char *cp, *start;
  1.3258 +	start = cp = s ? s : *state;
  1.3259 +	if (!cp)
  1.3260 +		return NULL;
  1.3261 +	while (*cp && !strchr(delim, *cp))
  1.3262 +		++cp;
  1.3263 +	if (!*cp) {
  1.3264 +		if (cp == start)
  1.3265 +			return NULL;
  1.3266 +		*state = NULL;
  1.3267 +		return start;
  1.3268 +	} else {
  1.3269 +		*cp++ = '\0';
  1.3270 +		*state = cp;
  1.3271 +		return start;
  1.3272 +	}
  1.3273 +}
  1.3274 +#endif
  1.3275 +
  1.3276 +/* helper version of atoi which returns -1 on error */
  1.3277 +static int
  1.3278 +strtoint(const char *const str)
  1.3279 +{
  1.3280 +	char *endptr;
  1.3281 +	const int r = strtol(str, &endptr, 10);
  1.3282 +	if (*endptr) return -1;
  1.3283 +	return r;
  1.3284 +}
  1.3285 +
  1.3286 +/* Parse a number of seconds into a timeval; return -1 on error. */
  1.3287 +static int
  1.3288 +strtotimeval(const char *const str, struct timeval *out)
  1.3289 +{
  1.3290 +	double d;
  1.3291 +	char *endptr;
  1.3292 +	d = strtod(str, &endptr);
  1.3293 +	if (*endptr) return -1;
  1.3294 +	if (d < 0) return -1;
  1.3295 +	out->tv_sec = (int) d;
  1.3296 +	out->tv_usec = (int) ((d - (int) d)*1000000);
  1.3297 +	if (out->tv_sec == 0 && out->tv_usec < 1000) /* less than 1 msec */
  1.3298 +		return -1;
  1.3299 +	return 0;
  1.3300 +}
  1.3301 +
  1.3302 +/* helper version of atoi that returns -1 on error and clips to bounds. */
  1.3303 +static int
  1.3304 +strtoint_clipped(const char *const str, int min, int max)
  1.3305 +{
  1.3306 +	int r = strtoint(str);
  1.3307 +	if (r == -1)
  1.3308 +		return r;
  1.3309 +	else if (r<min)
  1.3310 +		return min;
  1.3311 +	else if (r>max)
  1.3312 +		return max;
  1.3313 +	else
  1.3314 +		return r;
  1.3315 +}
  1.3316 +
  1.3317 +static int
  1.3318 +evdns_base_set_max_requests_inflight(struct evdns_base *base, int maxinflight)
  1.3319 +{
  1.3320 +	int old_n_heads = base->n_req_heads, n_heads;
  1.3321 +	struct request **old_heads = base->req_heads, **new_heads, *req;
  1.3322 +	int i;
  1.3323 +
  1.3324 +	ASSERT_LOCKED(base);
  1.3325 +	if (maxinflight < 1)
  1.3326 +		maxinflight = 1;
  1.3327 +	n_heads = (maxinflight+4) / 5;
  1.3328 +	EVUTIL_ASSERT(n_heads > 0);
  1.3329 +	new_heads = mm_calloc(n_heads, sizeof(struct request*));
  1.3330 +	if (!new_heads)
  1.3331 +		return (-1);
  1.3332 +	if (old_heads) {
  1.3333 +		for (i = 0; i < old_n_heads; ++i) {
  1.3334 +			while (old_heads[i]) {
  1.3335 +				req = old_heads[i];
  1.3336 +				evdns_request_remove(req, &old_heads[i]);
  1.3337 +				evdns_request_insert(req, &new_heads[req->trans_id % n_heads]);
  1.3338 +			}
  1.3339 +		}
  1.3340 +		mm_free(old_heads);
  1.3341 +	}
  1.3342 +	base->req_heads = new_heads;
  1.3343 +	base->n_req_heads = n_heads;
  1.3344 +	base->global_max_requests_inflight = maxinflight;
  1.3345 +	return (0);
  1.3346 +}
  1.3347 +
  1.3348 +/* exported function */
  1.3349 +int
  1.3350 +evdns_base_set_option(struct evdns_base *base,
  1.3351 +    const char *option, const char *val)
  1.3352 +{
  1.3353 +	int res;
  1.3354 +	EVDNS_LOCK(base);
  1.3355 +	res = evdns_base_set_option_impl(base, option, val, DNS_OPTIONS_ALL);
  1.3356 +	EVDNS_UNLOCK(base);
  1.3357 +	return res;
  1.3358 +}
  1.3359 +
  1.3360 +static inline int
  1.3361 +str_matches_option(const char *s1, const char *optionname)
  1.3362 +{
  1.3363 +	/* Option names are given as "option:" We accept either 'option' in
  1.3364 +	 * s1, or 'option:randomjunk'.  The latter form is to implement the
  1.3365 +	 * resolv.conf parser. */
  1.3366 +	size_t optlen = strlen(optionname);
  1.3367 +	size_t slen = strlen(s1);
  1.3368 +	if (slen == optlen || slen == optlen - 1)
  1.3369 +		return !strncmp(s1, optionname, slen);
  1.3370 +	else if (slen > optlen)
  1.3371 +		return !strncmp(s1, optionname, optlen);
  1.3372 +	else
  1.3373 +		return 0;
  1.3374 +}
  1.3375 +
  1.3376 +static int
  1.3377 +evdns_base_set_option_impl(struct evdns_base *base,
  1.3378 +    const char *option, const char *val, int flags)
  1.3379 +{
  1.3380 +	ASSERT_LOCKED(base);
  1.3381 +	if (str_matches_option(option, "ndots:")) {
  1.3382 +		const int ndots = strtoint(val);
  1.3383 +		if (ndots == -1) return -1;
  1.3384 +		if (!(flags & DNS_OPTION_SEARCH)) return 0;
  1.3385 +		log(EVDNS_LOG_DEBUG, "Setting ndots to %d", ndots);
  1.3386 +		if (!base->global_search_state) base->global_search_state = search_state_new();
  1.3387 +		if (!base->global_search_state) return -1;
  1.3388 +		base->global_search_state->ndots = ndots;
  1.3389 +	} else if (str_matches_option(option, "timeout:")) {
  1.3390 +		struct timeval tv;
  1.3391 +		if (strtotimeval(val, &tv) == -1) return -1;
  1.3392 +		if (!(flags & DNS_OPTION_MISC)) return 0;
  1.3393 +		log(EVDNS_LOG_DEBUG, "Setting timeout to %s", val);
  1.3394 +		memcpy(&base->global_timeout, &tv, sizeof(struct timeval));
  1.3395 +	} else if (str_matches_option(option, "getaddrinfo-allow-skew:")) {
  1.3396 +		struct timeval tv;
  1.3397 +		if (strtotimeval(val, &tv) == -1) return -1;
  1.3398 +		if (!(flags & DNS_OPTION_MISC)) return 0;
  1.3399 +		log(EVDNS_LOG_DEBUG, "Setting getaddrinfo-allow-skew to %s",
  1.3400 +		    val);
  1.3401 +		memcpy(&base->global_getaddrinfo_allow_skew, &tv,
  1.3402 +		    sizeof(struct timeval));
  1.3403 +	} else if (str_matches_option(option, "max-timeouts:")) {
  1.3404 +		const int maxtimeout = strtoint_clipped(val, 1, 255);
  1.3405 +		if (maxtimeout == -1) return -1;
  1.3406 +		if (!(flags & DNS_OPTION_MISC)) return 0;
  1.3407 +		log(EVDNS_LOG_DEBUG, "Setting maximum allowed timeouts to %d",
  1.3408 +			maxtimeout);
  1.3409 +		base->global_max_nameserver_timeout = maxtimeout;
  1.3410 +	} else if (str_matches_option(option, "max-inflight:")) {
  1.3411 +		const int maxinflight = strtoint_clipped(val, 1, 65000);
  1.3412 +		if (maxinflight == -1) return -1;
  1.3413 +		if (!(flags & DNS_OPTION_MISC)) return 0;
  1.3414 +		log(EVDNS_LOG_DEBUG, "Setting maximum inflight requests to %d",
  1.3415 +			maxinflight);
  1.3416 +		evdns_base_set_max_requests_inflight(base, maxinflight);
  1.3417 +	} else if (str_matches_option(option, "attempts:")) {
  1.3418 +		int retries = strtoint(val);
  1.3419 +		if (retries == -1) return -1;
  1.3420 +		if (retries > 255) retries = 255;
  1.3421 +		if (!(flags & DNS_OPTION_MISC)) return 0;
  1.3422 +		log(EVDNS_LOG_DEBUG, "Setting retries to %d", retries);
  1.3423 +		base->global_max_retransmits = retries;
  1.3424 +	} else if (str_matches_option(option, "randomize-case:")) {
  1.3425 +		int randcase = strtoint(val);
  1.3426 +		if (!(flags & DNS_OPTION_MISC)) return 0;
  1.3427 +		base->global_randomize_case = randcase;
  1.3428 +	} else if (str_matches_option(option, "bind-to:")) {
  1.3429 +		/* XXX This only applies to successive nameservers, not
  1.3430 +		 * to already-configured ones.	We might want to fix that. */
  1.3431 +		int len = sizeof(base->global_outgoing_address);
  1.3432 +		if (!(flags & DNS_OPTION_NAMESERVERS)) return 0;
  1.3433 +		if (evutil_parse_sockaddr_port(val,
  1.3434 +			(struct sockaddr*)&base->global_outgoing_address, &len))
  1.3435 +			return -1;
  1.3436 +		base->global_outgoing_addrlen = len;
  1.3437 +	} else if (str_matches_option(option, "initial-probe-timeout:")) {
  1.3438 +		struct timeval tv;
  1.3439 +		if (strtotimeval(val, &tv) == -1) return -1;
  1.3440 +		if (tv.tv_sec > 3600)
  1.3441 +			tv.tv_sec = 3600;
  1.3442 +		if (!(flags & DNS_OPTION_MISC)) return 0;
  1.3443 +		log(EVDNS_LOG_DEBUG, "Setting initial probe timeout to %s",
  1.3444 +		    val);
  1.3445 +		memcpy(&base->global_nameserver_probe_initial_timeout, &tv,
  1.3446 +		    sizeof(tv));
  1.3447 +	}
  1.3448 +	return 0;
  1.3449 +}
  1.3450 +
  1.3451 +int
  1.3452 +evdns_set_option(const char *option, const char *val, int flags)
  1.3453 +{
  1.3454 +	if (!current_base)
  1.3455 +		current_base = evdns_base_new(NULL, 0);
  1.3456 +	return evdns_base_set_option(current_base, option, val);
  1.3457 +}
  1.3458 +
  1.3459 +static void
  1.3460 +resolv_conf_parse_line(struct evdns_base *base, char *const start, int flags) {
  1.3461 +	char *strtok_state;
  1.3462 +	static const char *const delims = " \t";
  1.3463 +#define NEXT_TOKEN strtok_r(NULL, delims, &strtok_state)
  1.3464 +
  1.3465 +
  1.3466 +	char *const first_token = strtok_r(start, delims, &strtok_state);
  1.3467 +	ASSERT_LOCKED(base);
  1.3468 +	if (!first_token) return;
  1.3469 +
  1.3470 +	if (!strcmp(first_token, "nameserver") && (flags & DNS_OPTION_NAMESERVERS)) {
  1.3471 +		const char *const nameserver = NEXT_TOKEN;
  1.3472 +
  1.3473 +		if (nameserver)
  1.3474 +			evdns_base_nameserver_ip_add(base, nameserver);
  1.3475 +	} else if (!strcmp(first_token, "domain") && (flags & DNS_OPTION_SEARCH)) {
  1.3476 +		const char *const domain = NEXT_TOKEN;
  1.3477 +		if (domain) {
  1.3478 +			search_postfix_clear(base);
  1.3479 +			search_postfix_add(base, domain);
  1.3480 +		}
  1.3481 +	} else if (!strcmp(first_token, "search") && (flags & DNS_OPTION_SEARCH)) {
  1.3482 +		const char *domain;
  1.3483 +		search_postfix_clear(base);
  1.3484 +
  1.3485 +		while ((domain = NEXT_TOKEN)) {
  1.3486 +			search_postfix_add(base, domain);
  1.3487 +		}
  1.3488 +		search_reverse(base);
  1.3489 +	} else if (!strcmp(first_token, "options")) {
  1.3490 +		const char *option;
  1.3491 +		while ((option = NEXT_TOKEN)) {
  1.3492 +			const char *val = strchr(option, ':');
  1.3493 +			evdns_base_set_option_impl(base, option, val ? val+1 : "", flags);
  1.3494 +		}
  1.3495 +	}
  1.3496 +#undef NEXT_TOKEN
  1.3497 +}
  1.3498 +
  1.3499 +/* exported function */
  1.3500 +/* returns: */
  1.3501 +/*   0 no errors */
  1.3502 +/*   1 failed to open file */
  1.3503 +/*   2 failed to stat file */
  1.3504 +/*   3 file too large */
  1.3505 +/*   4 out of memory */
  1.3506 +/*   5 short read from file */
  1.3507 +int
  1.3508 +evdns_base_resolv_conf_parse(struct evdns_base *base, int flags, const char *const filename) {
  1.3509 +	int res;
  1.3510 +	EVDNS_LOCK(base);
  1.3511 +	res = evdns_base_resolv_conf_parse_impl(base, flags, filename);
  1.3512 +	EVDNS_UNLOCK(base);
  1.3513 +	return res;
  1.3514 +}
  1.3515 +
  1.3516 +static char *
  1.3517 +evdns_get_default_hosts_filename(void)
  1.3518 +{
  1.3519 +#ifdef WIN32
  1.3520 +	/* Windows is a little coy about where it puts its configuration
  1.3521 +	 * files.  Sure, they're _usually_ in C:\windows\system32, but
  1.3522 +	 * there's no reason in principle they couldn't be in
  1.3523 +	 * W:\hoboken chicken emergency\
  1.3524 +	 */
  1.3525 +	char path[MAX_PATH+1];
  1.3526 +	static const char hostfile[] = "\\drivers\\etc\\hosts";
  1.3527 +	char *path_out;
  1.3528 +	size_t len_out;
  1.3529 +
  1.3530 +	if (! SHGetSpecialFolderPathA(NULL, path, CSIDL_SYSTEM, 0))
  1.3531 +		return NULL;
  1.3532 +	len_out = strlen(path)+strlen(hostfile);
  1.3533 +	path_out = mm_malloc(len_out+1);
  1.3534 +	evutil_snprintf(path_out, len_out, "%s%s", path, hostfile);
  1.3535 +	return path_out;
  1.3536 +#else
  1.3537 +	return mm_strdup("/etc/hosts");
  1.3538 +#endif
  1.3539 +}
  1.3540 +
  1.3541 +static int
  1.3542 +evdns_base_resolv_conf_parse_impl(struct evdns_base *base, int flags, const char *const filename) {
  1.3543 +	size_t n;
  1.3544 +	char *resolv;
  1.3545 +	char *start;
  1.3546 +	int err = 0;
  1.3547 +
  1.3548 +	log(EVDNS_LOG_DEBUG, "Parsing resolv.conf file %s", filename);
  1.3549 +
  1.3550 +	if (flags & DNS_OPTION_HOSTSFILE) {
  1.3551 +		char *fname = evdns_get_default_hosts_filename();
  1.3552 +		evdns_base_load_hosts(base, fname);
  1.3553 +		if (fname)
  1.3554 +			mm_free(fname);
  1.3555 +	}
  1.3556 +
  1.3557 +	if ((err = evutil_read_file(filename, &resolv, &n, 0)) < 0) {
  1.3558 +		if (err == -1) {
  1.3559 +			/* No file. */
  1.3560 +			evdns_resolv_set_defaults(base, flags);
  1.3561 +			return 1;
  1.3562 +		} else {
  1.3563 +			return 2;
  1.3564 +		}
  1.3565 +	}
  1.3566 +
  1.3567 +	start = resolv;
  1.3568 +	for (;;) {
  1.3569 +		char *const newline = strchr(start, '\n');
  1.3570 +		if (!newline) {
  1.3571 +			resolv_conf_parse_line(base, start, flags);
  1.3572 +			break;
  1.3573 +		} else {
  1.3574 +			*newline = 0;
  1.3575 +			resolv_conf_parse_line(base, start, flags);
  1.3576 +			start = newline + 1;
  1.3577 +		}
  1.3578 +	}
  1.3579 +
  1.3580 +	if (!base->server_head && (flags & DNS_OPTION_NAMESERVERS)) {
  1.3581 +		/* no nameservers were configured. */
  1.3582 +		evdns_base_nameserver_ip_add(base, "127.0.0.1");
  1.3583 +		err = 6;
  1.3584 +	}
  1.3585 +	if (flags & DNS_OPTION_SEARCH && (!base->global_search_state || base->global_search_state->num_domains == 0)) {
  1.3586 +		search_set_from_hostname(base);
  1.3587 +	}
  1.3588 +
  1.3589 +	mm_free(resolv);
  1.3590 +	return err;
  1.3591 +}
  1.3592 +
  1.3593 +int
  1.3594 +evdns_resolv_conf_parse(int flags, const char *const filename) {
  1.3595 +	if (!current_base)
  1.3596 +		current_base = evdns_base_new(NULL, 0);
  1.3597 +	return evdns_base_resolv_conf_parse(current_base, flags, filename);
  1.3598 +}
  1.3599 +
  1.3600 +
  1.3601 +#ifdef WIN32
  1.3602 +/* Add multiple nameservers from a space-or-comma-separated list. */
  1.3603 +static int
  1.3604 +evdns_nameserver_ip_add_line(struct evdns_base *base, const char *ips) {
  1.3605 +	const char *addr;
  1.3606 +	char *buf;
  1.3607 +	int r;
  1.3608 +	ASSERT_LOCKED(base);
  1.3609 +	while (*ips) {
  1.3610 +		while (isspace(*ips) || *ips == ',' || *ips == '\t')
  1.3611 +			++ips;
  1.3612 +		addr = ips;
  1.3613 +		while (isdigit(*ips) || *ips == '.' || *ips == ':' ||
  1.3614 +		    *ips=='[' || *ips==']')
  1.3615 +			++ips;
  1.3616 +		buf = mm_malloc(ips-addr+1);
  1.3617 +		if (!buf) return 4;
  1.3618 +		memcpy(buf, addr, ips-addr);
  1.3619 +		buf[ips-addr] = '\0';
  1.3620 +		r = evdns_base_nameserver_ip_add(base, buf);
  1.3621 +		mm_free(buf);
  1.3622 +		if (r) return r;
  1.3623 +	}
  1.3624 +	return 0;
  1.3625 +}
  1.3626 +
  1.3627 +typedef DWORD(WINAPI *GetNetworkParams_fn_t)(FIXED_INFO *, DWORD*);
  1.3628 +
  1.3629 +/* Use the windows GetNetworkParams interface in iphlpapi.dll to */
  1.3630 +/* figure out what our nameservers are. */
  1.3631 +static int
  1.3632 +load_nameservers_with_getnetworkparams(struct evdns_base *base)
  1.3633 +{
  1.3634 +	/* Based on MSDN examples and inspection of  c-ares code. */
  1.3635 +	FIXED_INFO *fixed;
  1.3636 +	HMODULE handle = 0;
  1.3637 +	ULONG size = sizeof(FIXED_INFO);
  1.3638 +	void *buf = NULL;
  1.3639 +	int status = 0, r, added_any;
  1.3640 +	IP_ADDR_STRING *ns;
  1.3641 +	GetNetworkParams_fn_t fn;
  1.3642 +
  1.3643 +	ASSERT_LOCKED(base);
  1.3644 +	if (!(handle = evutil_load_windows_system_library(
  1.3645 +			TEXT("iphlpapi.dll")))) {
  1.3646 +		log(EVDNS_LOG_WARN, "Could not open iphlpapi.dll");
  1.3647 +		status = -1;
  1.3648 +		goto done;
  1.3649 +	}
  1.3650 +	if (!(fn = (GetNetworkParams_fn_t) GetProcAddress(handle, "GetNetworkParams"))) {
  1.3651 +		log(EVDNS_LOG_WARN, "Could not get address of function.");
  1.3652 +		status = -1;
  1.3653 +		goto done;
  1.3654 +	}
  1.3655 +
  1.3656 +	buf = mm_malloc(size);
  1.3657 +	if (!buf) { status = 4; goto done; }
  1.3658 +	fixed = buf;
  1.3659 +	r = fn(fixed, &size);
  1.3660 +	if (r != ERROR_SUCCESS && r != ERROR_BUFFER_OVERFLOW) {
  1.3661 +		status = -1;
  1.3662 +		goto done;
  1.3663 +	}
  1.3664 +	if (r != ERROR_SUCCESS) {
  1.3665 +		mm_free(buf);
  1.3666 +		buf = mm_malloc(size);
  1.3667 +		if (!buf) { status = 4; goto done; }
  1.3668 +		fixed = buf;
  1.3669 +		r = fn(fixed, &size);
  1.3670 +		if (r != ERROR_SUCCESS) {
  1.3671 +			log(EVDNS_LOG_DEBUG, "fn() failed.");
  1.3672 +			status = -1;
  1.3673 +			goto done;
  1.3674 +		}
  1.3675 +	}
  1.3676 +
  1.3677 +	EVUTIL_ASSERT(fixed);
  1.3678 +	added_any = 0;
  1.3679 +	ns = &(fixed->DnsServerList);
  1.3680 +	while (ns) {
  1.3681 +		r = evdns_nameserver_ip_add_line(base, ns->IpAddress.String);
  1.3682 +		if (r) {
  1.3683 +			log(EVDNS_LOG_DEBUG,"Could not add nameserver %s to list,error: %d",
  1.3684 +				(ns->IpAddress.String),(int)GetLastError());
  1.3685 +			status = r;
  1.3686 +		} else {
  1.3687 +			++added_any;
  1.3688 +			log(EVDNS_LOG_DEBUG,"Successfully added %s as nameserver",ns->IpAddress.String);
  1.3689 +		}
  1.3690 +
  1.3691 +		ns = ns->Next;
  1.3692 +	}
  1.3693 +
  1.3694 +	if (!added_any) {
  1.3695 +		log(EVDNS_LOG_DEBUG, "No nameservers added.");
  1.3696 +		if (status == 0)
  1.3697 +			status = -1;
  1.3698 +	} else {
  1.3699 +		status = 0;
  1.3700 +	}
  1.3701 +
  1.3702 + done:
  1.3703 +	if (buf)
  1.3704 +		mm_free(buf);
  1.3705 +	if (handle)
  1.3706 +		FreeLibrary(handle);
  1.3707 +	return status;
  1.3708 +}
  1.3709 +
  1.3710 +static int
  1.3711 +config_nameserver_from_reg_key(struct evdns_base *base, HKEY key, const TCHAR *subkey)
  1.3712 +{
  1.3713 +	char *buf;
  1.3714 +	DWORD bufsz = 0, type = 0;
  1.3715 +	int status = 0;
  1.3716 +
  1.3717 +	ASSERT_LOCKED(base);
  1.3718 +	if (RegQueryValueEx(key, subkey, 0, &type, NULL, &bufsz)
  1.3719 +	    != ERROR_MORE_DATA)
  1.3720 +		return -1;
  1.3721 +	if (!(buf = mm_malloc(bufsz)))
  1.3722 +		return -1;
  1.3723 +
  1.3724 +	if (RegQueryValueEx(key, subkey, 0, &type, (LPBYTE)buf, &bufsz)
  1.3725 +	    == ERROR_SUCCESS && bufsz > 1) {
  1.3726 +		status = evdns_nameserver_ip_add_line(base,buf);
  1.3727 +	}
  1.3728 +
  1.3729 +	mm_free(buf);
  1.3730 +	return status;
  1.3731 +}
  1.3732 +
  1.3733 +#define SERVICES_KEY TEXT("System\\CurrentControlSet\\Services\\")
  1.3734 +#define WIN_NS_9X_KEY  SERVICES_KEY TEXT("VxD\\MSTCP")
  1.3735 +#define WIN_NS_NT_KEY  SERVICES_KEY TEXT("Tcpip\\Parameters")
  1.3736 +
  1.3737 +static int
  1.3738 +load_nameservers_from_registry(struct evdns_base *base)
  1.3739 +{
  1.3740 +	int found = 0;
  1.3741 +	int r;
  1.3742 +#define TRY(k, name) \
  1.3743 +	if (!found && config_nameserver_from_reg_key(base,k,TEXT(name)) == 0) { \
  1.3744 +		log(EVDNS_LOG_DEBUG,"Found nameservers in %s/%s",#k,name); \
  1.3745 +		found = 1;						\
  1.3746 +	} else if (!found) {						\
  1.3747 +		log(EVDNS_LOG_DEBUG,"Didn't find nameservers in %s/%s", \
  1.3748 +		    #k,#name);						\
  1.3749 +	}
  1.3750 +
  1.3751 +	ASSERT_LOCKED(base);
  1.3752 +
  1.3753 +	if (((int)GetVersion()) > 0) { /* NT */
  1.3754 +		HKEY nt_key = 0, interfaces_key = 0;
  1.3755 +
  1.3756 +		if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0,
  1.3757 +				 KEY_READ, &nt_key) != ERROR_SUCCESS) {
  1.3758 +			log(EVDNS_LOG_DEBUG,"Couldn't open nt key, %d",(int)GetLastError());
  1.3759 +			return -1;
  1.3760 +		}
  1.3761 +		r = RegOpenKeyEx(nt_key, TEXT("Interfaces"), 0,
  1.3762 +			     KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS,
  1.3763 +			     &interfaces_key);
  1.3764 +		if (r != ERROR_SUCCESS) {
  1.3765 +			log(EVDNS_LOG_DEBUG,"Couldn't open interfaces key, %d",(int)GetLastError());
  1.3766 +			return -1;
  1.3767 +		}
  1.3768 +		TRY(nt_key, "NameServer");
  1.3769 +		TRY(nt_key, "DhcpNameServer");
  1.3770 +		TRY(interfaces_key, "NameServer");
  1.3771 +		TRY(interfaces_key, "DhcpNameServer");
  1.3772 +		RegCloseKey(interfaces_key);
  1.3773 +		RegCloseKey(nt_key);
  1.3774 +	} else {
  1.3775 +		HKEY win_key = 0;
  1.3776 +		if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_9X_KEY, 0,
  1.3777 +				 KEY_READ, &win_key) != ERROR_SUCCESS) {
  1.3778 +			log(EVDNS_LOG_DEBUG, "Couldn't open registry key, %d", (int)GetLastError());
  1.3779 +			return -1;
  1.3780 +		}
  1.3781 +		TRY(win_key, "NameServer");
  1.3782 +		RegCloseKey(win_key);
  1.3783 +	}
  1.3784 +
  1.3785 +	if (found == 0) {
  1.3786 +		log(EVDNS_LOG_WARN,"Didn't find any nameservers.");
  1.3787 +	}
  1.3788 +
  1.3789 +	return found ? 0 : -1;
  1.3790 +#undef TRY
  1.3791 +}
  1.3792 +
  1.3793 +int
  1.3794 +evdns_base_config_windows_nameservers(struct evdns_base *base)
  1.3795 +{
  1.3796 +	int r;
  1.3797 +	char *fname;
  1.3798 +	if (base == NULL)
  1.3799 +		base = current_base;
  1.3800 +	if (base == NULL)
  1.3801 +		return -1;
  1.3802 +	EVDNS_LOCK(base);
  1.3803 +	if (load_nameservers_with_getnetworkparams(base) == 0) {
  1.3804 +		EVDNS_UNLOCK(base);
  1.3805 +		return 0;
  1.3806 +	}
  1.3807 +	r = load_nameservers_from_registry(base);
  1.3808 +
  1.3809 +	fname = evdns_get_default_hosts_filename();
  1.3810 +	evdns_base_load_hosts(base, fname);
  1.3811 +	if (fname)
  1.3812 +		mm_free(fname);
  1.3813 +
  1.3814 +	EVDNS_UNLOCK(base);
  1.3815 +	return r;
  1.3816 +}
  1.3817 +
  1.3818 +int
  1.3819 +evdns_config_windows_nameservers(void)
  1.3820 +{
  1.3821 +	if (!current_base) {
  1.3822 +		current_base = evdns_base_new(NULL, 1);
  1.3823 +		return current_base == NULL ? -1 : 0;
  1.3824 +	} else {
  1.3825 +		return evdns_base_config_windows_nameservers(current_base);
  1.3826 +	}
  1.3827 +}
  1.3828 +#endif
  1.3829 +
  1.3830 +struct evdns_base *
  1.3831 +evdns_base_new(struct event_base *event_base, int initialize_nameservers)
  1.3832 +{
  1.3833 +	struct evdns_base *base;
  1.3834 +
  1.3835 +	if (evutil_secure_rng_init() < 0) {
  1.3836 +		log(EVDNS_LOG_WARN, "Unable to seed random number generator; "
  1.3837 +		    "DNS can't run.");
  1.3838 +		return NULL;
  1.3839 +	}
  1.3840 +
  1.3841 +	/* Give the evutil library a hook into its evdns-enabled
  1.3842 +	 * functionality.  We can't just call evdns_getaddrinfo directly or
  1.3843 +	 * else libevent-core will depend on libevent-extras. */
  1.3844 +	evutil_set_evdns_getaddrinfo_fn(evdns_getaddrinfo);
  1.3845 +
  1.3846 +	base = mm_malloc(sizeof(struct evdns_base));
  1.3847 +	if (base == NULL)
  1.3848 +		return (NULL);
  1.3849 +	memset(base, 0, sizeof(struct evdns_base));
  1.3850 +	base->req_waiting_head = NULL;
  1.3851 +
  1.3852 +	EVTHREAD_ALLOC_LOCK(base->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
  1.3853 +	EVDNS_LOCK(base);
  1.3854 +
  1.3855 +	/* Set max requests inflight and allocate req_heads. */
  1.3856 +	base->req_heads = NULL;
  1.3857 +
  1.3858 +	evdns_base_set_max_requests_inflight(base, 64);
  1.3859 +
  1.3860 +	base->server_head = NULL;
  1.3861 +	base->event_base = event_base;
  1.3862 +	base->global_good_nameservers = base->global_requests_inflight =
  1.3863 +		base->global_requests_waiting = 0;
  1.3864 +
  1.3865 +	base->global_timeout.tv_sec = 5;
  1.3866 +	base->global_timeout.tv_usec = 0;
  1.3867 +	base->global_max_reissues = 1;
  1.3868 +	base->global_max_retransmits = 3;
  1.3869 +	base->global_max_nameserver_timeout = 3;
  1.3870 +	base->global_search_state = NULL;
  1.3871 +	base->global_randomize_case = 1;
  1.3872 +	base->global_getaddrinfo_allow_skew.tv_sec = 3;
  1.3873 +	base->global_getaddrinfo_allow_skew.tv_usec = 0;
  1.3874 +	base->global_nameserver_probe_initial_timeout.tv_sec = 10;
  1.3875 +	base->global_nameserver_probe_initial_timeout.tv_usec = 0;
  1.3876 +
  1.3877 +	TAILQ_INIT(&base->hostsdb);
  1.3878 +
  1.3879 +	if (initialize_nameservers) {
  1.3880 +		int r;
  1.3881 +#ifdef WIN32
  1.3882 +		r = evdns_base_config_windows_nameservers(base);
  1.3883 +#else
  1.3884 +		r = evdns_base_resolv_conf_parse(base, DNS_OPTIONS_ALL, "/etc/resolv.conf");
  1.3885 +#endif
  1.3886 +		if (r == -1) {
  1.3887 +			evdns_base_free_and_unlock(base, 0);
  1.3888 +			return NULL;
  1.3889 +		}
  1.3890 +	}
  1.3891 +	EVDNS_UNLOCK(base);
  1.3892 +	return base;
  1.3893 +}
  1.3894 +
  1.3895 +int
  1.3896 +evdns_init(void)
  1.3897 +{
  1.3898 +	struct evdns_base *base = evdns_base_new(NULL, 1);
  1.3899 +	if (base) {
  1.3900 +		current_base = base;
  1.3901 +		return 0;
  1.3902 +	} else {
  1.3903 +		return -1;
  1.3904 +	}
  1.3905 +}
  1.3906 +
  1.3907 +const char *
  1.3908 +evdns_err_to_string(int err)
  1.3909 +{
  1.3910 +    switch (err) {
  1.3911 +	case DNS_ERR_NONE: return "no error";
  1.3912 +	case DNS_ERR_FORMAT: return "misformatted query";
  1.3913 +	case DNS_ERR_SERVERFAILED: return "server failed";
  1.3914 +	case DNS_ERR_NOTEXIST: return "name does not exist";
  1.3915 +	case DNS_ERR_NOTIMPL: return "query not implemented";
  1.3916 +	case DNS_ERR_REFUSED: return "refused";
  1.3917 +
  1.3918 +	case DNS_ERR_TRUNCATED: return "reply truncated or ill-formed";
  1.3919 +	case DNS_ERR_UNKNOWN: return "unknown";
  1.3920 +	case DNS_ERR_TIMEOUT: return "request timed out";
  1.3921 +	case DNS_ERR_SHUTDOWN: return "dns subsystem shut down";
  1.3922 +	case DNS_ERR_CANCEL: return "dns request canceled";
  1.3923 +	case DNS_ERR_NODATA: return "no records in the reply";
  1.3924 +	default: return "[Unknown error code]";
  1.3925 +    }
  1.3926 +}
  1.3927 +
  1.3928 +static void
  1.3929 +evdns_nameserver_free(struct nameserver *server)
  1.3930 +{
  1.3931 +	if (server->socket >= 0)
  1.3932 +	evutil_closesocket(server->socket);
  1.3933 +	(void) event_del(&server->event);
  1.3934 +	event_debug_unassign(&server->event);
  1.3935 +	if (server->state == 0)
  1.3936 +		(void) event_del(&server->timeout_event);
  1.3937 +	event_debug_unassign(&server->timeout_event);
  1.3938 +	mm_free(server);
  1.3939 +}
  1.3940 +
  1.3941 +static void
  1.3942 +evdns_base_free_and_unlock(struct evdns_base *base, int fail_requests)
  1.3943 +{
  1.3944 +	struct nameserver *server, *server_next;
  1.3945 +	struct search_domain *dom, *dom_next;
  1.3946 +	int i;
  1.3947 +
  1.3948 +	/* Requires that we hold the lock. */
  1.3949 +
  1.3950 +	/* TODO(nickm) we might need to refcount here. */
  1.3951 +
  1.3952 +	for (i = 0; i < base->n_req_heads; ++i) {
  1.3953 +		while (base->req_heads[i]) {
  1.3954 +			if (fail_requests)
  1.3955 +				reply_schedule_callback(base->req_heads[i], 0, DNS_ERR_SHUTDOWN, NULL);
  1.3956 +			request_finished(base->req_heads[i], &REQ_HEAD(base, base->req_heads[i]->trans_id), 1);
  1.3957 +		}
  1.3958 +	}
  1.3959 +	while (base->req_waiting_head) {
  1.3960 +		if (fail_requests)
  1.3961 +			reply_schedule_callback(base->req_waiting_head, 0, DNS_ERR_SHUTDOWN, NULL);
  1.3962 +		request_finished(base->req_waiting_head, &base->req_waiting_head, 1);
  1.3963 +	}
  1.3964 +	base->global_requests_inflight = base->global_requests_waiting = 0;
  1.3965 +
  1.3966 +	for (server = base->server_head; server; server = server_next) {
  1.3967 +		server_next = server->next;
  1.3968 +		evdns_nameserver_free(server);
  1.3969 +		if (server_next == base->server_head)
  1.3970 +			break;
  1.3971 +	}
  1.3972 +	base->server_head = NULL;
  1.3973 +	base->global_good_nameservers = 0;
  1.3974 +
  1.3975 +	if (base->global_search_state) {
  1.3976 +		for (dom = base->global_search_state->head; dom; dom = dom_next) {
  1.3977 +			dom_next = dom->next;
  1.3978 +			mm_free(dom);
  1.3979 +		}
  1.3980 +		mm_free(base->global_search_state);
  1.3981 +		base->global_search_state = NULL;
  1.3982 +	}
  1.3983 +
  1.3984 +	{
  1.3985 +		struct hosts_entry *victim;
  1.3986 +		while ((victim = TAILQ_FIRST(&base->hostsdb))) {
  1.3987 +			TAILQ_REMOVE(&base->hostsdb, victim, next);
  1.3988 +			mm_free(victim);
  1.3989 +		}
  1.3990 +	}
  1.3991 +
  1.3992 +	mm_free(base->req_heads);
  1.3993 +
  1.3994 +	EVDNS_UNLOCK(base);
  1.3995 +	EVTHREAD_FREE_LOCK(base->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
  1.3996 +
  1.3997 +	mm_free(base);
  1.3998 +}
  1.3999 +
  1.4000 +void
  1.4001 +evdns_base_free(struct evdns_base *base, int fail_requests)
  1.4002 +{
  1.4003 +	EVDNS_LOCK(base);
  1.4004 +	evdns_base_free_and_unlock(base, fail_requests);
  1.4005 +}
  1.4006 +
  1.4007 +void
  1.4008 +evdns_shutdown(int fail_requests)
  1.4009 +{
  1.4010 +	if (current_base) {
  1.4011 +		struct evdns_base *b = current_base;
  1.4012 +		current_base = NULL;
  1.4013 +		evdns_base_free(b, fail_requests);
  1.4014 +	}
  1.4015 +	evdns_log_fn = NULL;
  1.4016 +}
  1.4017 +
  1.4018 +static int
  1.4019 +evdns_base_parse_hosts_line(struct evdns_base *base, char *line)
  1.4020 +{
  1.4021 +	char *strtok_state;
  1.4022 +	static const char *const delims = " \t";
  1.4023 +	char *const addr = strtok_r(line, delims, &strtok_state);
  1.4024 +	char *hostname, *hash;
  1.4025 +	struct sockaddr_storage ss;
  1.4026 +	int socklen = sizeof(ss);
  1.4027 +	ASSERT_LOCKED(base);
  1.4028 +
  1.4029 +#define NEXT_TOKEN strtok_r(NULL, delims, &strtok_state)
  1.4030 +
  1.4031 +	if (!addr || *addr == '#')
  1.4032 +		return 0;
  1.4033 +
  1.4034 +	memset(&ss, 0, sizeof(ss));
  1.4035 +	if (evutil_parse_sockaddr_port(addr, (struct sockaddr*)&ss, &socklen)<0)
  1.4036 +		return -1;
  1.4037 +	if (socklen > (int)sizeof(struct sockaddr_in6))
  1.4038 +		return -1;
  1.4039 +
  1.4040 +	if (sockaddr_getport((struct sockaddr*)&ss))
  1.4041 +		return -1;
  1.4042 +
  1.4043 +	while ((hostname = NEXT_TOKEN)) {
  1.4044 +		struct hosts_entry *he;
  1.4045 +		size_t namelen;
  1.4046 +		if ((hash = strchr(hostname, '#'))) {
  1.4047 +			if (hash == hostname)
  1.4048 +				return 0;
  1.4049 +			*hash = '\0';
  1.4050 +		}
  1.4051 +
  1.4052 +		namelen = strlen(hostname);
  1.4053 +
  1.4054 +		he = mm_calloc(1, sizeof(struct hosts_entry)+namelen);
  1.4055 +		if (!he)
  1.4056 +			return -1;
  1.4057 +		EVUTIL_ASSERT(socklen <= (int)sizeof(he->addr));
  1.4058 +		memcpy(&he->addr, &ss, socklen);
  1.4059 +		memcpy(he->hostname, hostname, namelen+1);
  1.4060 +		he->addrlen = socklen;
  1.4061 +
  1.4062 +		TAILQ_INSERT_TAIL(&base->hostsdb, he, next);
  1.4063 +
  1.4064 +		if (hash)
  1.4065 +			return 0;
  1.4066 +	}
  1.4067 +
  1.4068 +	return 0;
  1.4069 +#undef NEXT_TOKEN
  1.4070 +}
  1.4071 +
  1.4072 +static int
  1.4073 +evdns_base_load_hosts_impl(struct evdns_base *base, const char *hosts_fname)
  1.4074 +{
  1.4075 +	char *str=NULL, *cp, *eol;
  1.4076 +	size_t len;
  1.4077 +	int err=0;
  1.4078 +
  1.4079 +	ASSERT_LOCKED(base);
  1.4080 +
  1.4081 +	if (hosts_fname == NULL ||
  1.4082 +	    (err = evutil_read_file(hosts_fname, &str, &len, 0)) < 0) {
  1.4083 +		char tmp[64];
  1.4084 +		strlcpy(tmp, "127.0.0.1   localhost", sizeof(tmp));
  1.4085 +		evdns_base_parse_hosts_line(base, tmp);
  1.4086 +		strlcpy(tmp, "::1   localhost", sizeof(tmp));
  1.4087 +		evdns_base_parse_hosts_line(base, tmp);
  1.4088 +		return err ? -1 : 0;
  1.4089 +	}
  1.4090 +
  1.4091 +	/* This will break early if there is a NUL in the hosts file.
  1.4092 +	 * Probably not a problem.*/
  1.4093 +	cp = str;
  1.4094 +	for (;;) {
  1.4095 +		eol = strchr(cp, '\n');
  1.4096 +
  1.4097 +		if (eol) {
  1.4098 +			*eol = '\0';
  1.4099 +			evdns_base_parse_hosts_line(base, cp);
  1.4100 +			cp = eol+1;
  1.4101 +		} else {
  1.4102 +			evdns_base_parse_hosts_line(base, cp);
  1.4103 +			break;
  1.4104 +		}
  1.4105 +	}
  1.4106 +
  1.4107 +	mm_free(str);
  1.4108 +	return 0;
  1.4109 +}
  1.4110 +
  1.4111 +int
  1.4112 +evdns_base_load_hosts(struct evdns_base *base, const char *hosts_fname)
  1.4113 +{
  1.4114 +	int res;
  1.4115 +	if (!base)
  1.4116 +		base = current_base;
  1.4117 +	EVDNS_LOCK(base);
  1.4118 +	res = evdns_base_load_hosts_impl(base, hosts_fname);
  1.4119 +	EVDNS_UNLOCK(base);
  1.4120 +	return res;
  1.4121 +}
  1.4122 +
  1.4123 +/* A single request for a getaddrinfo, either v4 or v6. */
  1.4124 +struct getaddrinfo_subrequest {
  1.4125 +	struct evdns_request *r;
  1.4126 +	ev_uint32_t type;
  1.4127 +};
  1.4128 +
  1.4129 +/* State data used to implement an in-progress getaddrinfo. */
  1.4130 +struct evdns_getaddrinfo_request {
  1.4131 +	struct evdns_base *evdns_base;
  1.4132 +	/* Copy of the modified 'hints' data that we'll use to build
  1.4133 +	 * answers. */
  1.4134 +	struct evutil_addrinfo hints;
  1.4135 +	/* The callback to invoke when we're done */
  1.4136 +	evdns_getaddrinfo_cb user_cb;
  1.4137 +	/* User-supplied data to give to the callback. */
  1.4138 +	void *user_data;
  1.4139 +	/* The port to use when building sockaddrs. */
  1.4140 +	ev_uint16_t port;
  1.4141 +	/* The sub_request for an A record (if any) */
  1.4142 +	struct getaddrinfo_subrequest ipv4_request;
  1.4143 +	/* The sub_request for an AAAA record (if any) */
  1.4144 +	struct getaddrinfo_subrequest ipv6_request;
  1.4145 +
  1.4146 +	/* The cname result that we were told (if any) */
  1.4147 +	char *cname_result;
  1.4148 +
  1.4149 +	/* If we have one request answered and one request still inflight,
  1.4150 +	 * then this field holds the answer from the first request... */
  1.4151 +	struct evutil_addrinfo *pending_result;
  1.4152 +	/* And this event is a timeout that will tell us to cancel the second
  1.4153 +	 * request if it's taking a long time. */
  1.4154 +	struct event timeout;
  1.4155 +
  1.4156 +	/* And this field holds the error code from the first request... */
  1.4157 +	int pending_error;
  1.4158 +	/* If this is set, the user canceled this request. */
  1.4159 +	unsigned user_canceled : 1;
  1.4160 +	/* If this is set, the user can no longer cancel this request; we're
  1.4161 +	 * just waiting for the free. */
  1.4162 +	unsigned request_done : 1;
  1.4163 +};
  1.4164 +
  1.4165 +/* Convert an evdns errors to the equivalent getaddrinfo error. */
  1.4166 +static int
  1.4167 +evdns_err_to_getaddrinfo_err(int e1)
  1.4168 +{
  1.4169 +	/* XXX Do this better! */
  1.4170 +	if (e1 == DNS_ERR_NONE)
  1.4171 +		return 0;
  1.4172 +	else if (e1 == DNS_ERR_NOTEXIST)
  1.4173 +		return EVUTIL_EAI_NONAME;
  1.4174 +	else
  1.4175 +		return EVUTIL_EAI_FAIL;
  1.4176 +}
  1.4177 +
  1.4178 +/* Return the more informative of two getaddrinfo errors. */
  1.4179 +static int
  1.4180 +getaddrinfo_merge_err(int e1, int e2)
  1.4181 +{
  1.4182 +	/* XXXX be cleverer here. */
  1.4183 +	if (e1 == 0)
  1.4184 +		return e2;
  1.4185 +	else
  1.4186 +		return e1;
  1.4187 +}
  1.4188 +
  1.4189 +static void
  1.4190 +free_getaddrinfo_request(struct evdns_getaddrinfo_request *data)
  1.4191 +{
  1.4192 +	/* DO NOT CALL this if either of the requests is pending.  Only once
  1.4193 +	 * both callbacks have been invoked is it safe to free the request */
  1.4194 +	if (data->pending_result)
  1.4195 +		evutil_freeaddrinfo(data->pending_result);
  1.4196 +	if (data->cname_result)
  1.4197 +		mm_free(data->cname_result);
  1.4198 +	event_del(&data->timeout);
  1.4199 +	mm_free(data);
  1.4200 +	return;
  1.4201 +}
  1.4202 +
  1.4203 +static void
  1.4204 +add_cname_to_reply(struct evdns_getaddrinfo_request *data,
  1.4205 +    struct evutil_addrinfo *ai)
  1.4206 +{
  1.4207 +	if (data->cname_result && ai) {
  1.4208 +		ai->ai_canonname = data->cname_result;
  1.4209 +		data->cname_result = NULL;
  1.4210 +	}
  1.4211 +}
  1.4212 +
  1.4213 +/* Callback: invoked when one request in a mixed-format A/AAAA getaddrinfo
  1.4214 + * request has finished, but the other one took too long to answer. Pass
  1.4215 + * along the answer we got, and cancel the other request.
  1.4216 + */
  1.4217 +static void
  1.4218 +evdns_getaddrinfo_timeout_cb(evutil_socket_t fd, short what, void *ptr)
  1.4219 +{
  1.4220 +	int v4_timedout = 0, v6_timedout = 0;
  1.4221 +	struct evdns_getaddrinfo_request *data = ptr;
  1.4222 +
  1.4223 +	/* Cancel any pending requests, and note which one */
  1.4224 +	if (data->ipv4_request.r) {
  1.4225 +		/* XXXX This does nothing if the request's callback is already
  1.4226 +		 * running (pending_cb is set). */
  1.4227 +		evdns_cancel_request(NULL, data->ipv4_request.r);
  1.4228 +		v4_timedout = 1;
  1.4229 +		EVDNS_LOCK(data->evdns_base);
  1.4230 +		++data->evdns_base->getaddrinfo_ipv4_timeouts;
  1.4231 +		EVDNS_UNLOCK(data->evdns_base);
  1.4232 +	}
  1.4233 +	if (data->ipv6_request.r) {
  1.4234 +		/* XXXX This does nothing if the request's callback is already
  1.4235 +		 * running (pending_cb is set). */
  1.4236 +		evdns_cancel_request(NULL, data->ipv6_request.r);
  1.4237 +		v6_timedout = 1;
  1.4238 +		EVDNS_LOCK(data->evdns_base);
  1.4239 +		++data->evdns_base->getaddrinfo_ipv6_timeouts;
  1.4240 +		EVDNS_UNLOCK(data->evdns_base);
  1.4241 +	}
  1.4242 +
  1.4243 +	/* We only use this timeout callback when we have an answer for
  1.4244 +	 * one address. */
  1.4245 +	EVUTIL_ASSERT(!v4_timedout || !v6_timedout);
  1.4246 +
  1.4247 +	/* Report the outcome of the other request that didn't time out. */
  1.4248 +	if (data->pending_result) {
  1.4249 +		add_cname_to_reply(data, data->pending_result);
  1.4250 +		data->user_cb(0, data->pending_result, data->user_data);
  1.4251 +		data->pending_result = NULL;
  1.4252 +	} else {
  1.4253 +		int e = data->pending_error;
  1.4254 +		if (!e)
  1.4255 +			e = EVUTIL_EAI_AGAIN;
  1.4256 +		data->user_cb(e, NULL, data->user_data);
  1.4257 +	}
  1.4258 +
  1.4259 +	data->user_cb = NULL; /* prevent double-call if evdns callbacks are
  1.4260 +			       * in-progress. XXXX It would be better if this
  1.4261 +			       * weren't necessary. */
  1.4262 +
  1.4263 +	if (!v4_timedout && !v6_timedout) {
  1.4264 +		/* should be impossible? XXXX */
  1.4265 +		free_getaddrinfo_request(data);
  1.4266 +	}
  1.4267 +}
  1.4268 +
  1.4269 +static int
  1.4270 +evdns_getaddrinfo_set_timeout(struct evdns_base *evdns_base,
  1.4271 +    struct evdns_getaddrinfo_request *data)
  1.4272 +{
  1.4273 +	return event_add(&data->timeout, &evdns_base->global_getaddrinfo_allow_skew);
  1.4274 +}
  1.4275 +
  1.4276 +static inline int
  1.4277 +evdns_result_is_answer(int result)
  1.4278 +{
  1.4279 +	return (result != DNS_ERR_NOTIMPL && result != DNS_ERR_REFUSED &&
  1.4280 +	    result != DNS_ERR_SERVERFAILED && result != DNS_ERR_CANCEL);
  1.4281 +}
  1.4282 +
  1.4283 +static void
  1.4284 +evdns_getaddrinfo_gotresolve(int result, char type, int count,
  1.4285 +    int ttl, void *addresses, void *arg)
  1.4286 +{
  1.4287 +	int i;
  1.4288 +	struct getaddrinfo_subrequest *req = arg;
  1.4289 +	struct getaddrinfo_subrequest *other_req;
  1.4290 +	struct evdns_getaddrinfo_request *data;
  1.4291 +
  1.4292 +	struct evutil_addrinfo *res;
  1.4293 +
  1.4294 +	struct sockaddr_in sin;
  1.4295 +	struct sockaddr_in6 sin6;
  1.4296 +	struct sockaddr *sa;
  1.4297 +	int socklen, addrlen;
  1.4298 +	void *addrp;
  1.4299 +	int err;
  1.4300 +	int user_canceled;
  1.4301 +
  1.4302 +	EVUTIL_ASSERT(req->type == DNS_IPv4_A || req->type == DNS_IPv6_AAAA);
  1.4303 +	if (req->type == DNS_IPv4_A) {
  1.4304 +		data = EVUTIL_UPCAST(req, struct evdns_getaddrinfo_request, ipv4_request);
  1.4305 +		other_req = &data->ipv6_request;
  1.4306 +	} else {
  1.4307 +		data = EVUTIL_UPCAST(req, struct evdns_getaddrinfo_request, ipv6_request);
  1.4308 +		other_req = &data->ipv4_request;
  1.4309 +	}
  1.4310 +
  1.4311 +	EVDNS_LOCK(data->evdns_base);
  1.4312 +	if (evdns_result_is_answer(result)) {
  1.4313 +		if (req->type == DNS_IPv4_A)
  1.4314 +			++data->evdns_base->getaddrinfo_ipv4_answered;
  1.4315 +		else
  1.4316 +			++data->evdns_base->getaddrinfo_ipv6_answered;
  1.4317 +	}
  1.4318 +	user_canceled = data->user_canceled;
  1.4319 +	if (other_req->r == NULL)
  1.4320 +		data->request_done = 1;
  1.4321 +	EVDNS_UNLOCK(data->evdns_base);
  1.4322 +
  1.4323 +	req->r = NULL;
  1.4324 +
  1.4325 +	if (result == DNS_ERR_CANCEL && ! user_canceled) {
  1.4326 +		/* Internal cancel request from timeout or internal error.
  1.4327 +		 * we already answered the user. */
  1.4328 +		if (other_req->r == NULL)
  1.4329 +			free_getaddrinfo_request(data);
  1.4330 +		return;
  1.4331 +	}
  1.4332 +
  1.4333 +	if (data->user_cb == NULL) {
  1.4334 +		/* We already answered.  XXXX This shouldn't be needed; see
  1.4335 +		 * comments in evdns_getaddrinfo_timeout_cb */
  1.4336 +		free_getaddrinfo_request(data);
  1.4337 +		return;
  1.4338 +	}
  1.4339 +
  1.4340 +	if (result == DNS_ERR_NONE) {
  1.4341 +		if (count == 0)
  1.4342 +			err = EVUTIL_EAI_NODATA;
  1.4343 +		else
  1.4344 +			err = 0;
  1.4345 +	} else {
  1.4346 +		err = evdns_err_to_getaddrinfo_err(result);
  1.4347 +	}
  1.4348 +
  1.4349 +	if (err) {
  1.4350 +		/* Looks like we got an error. */
  1.4351 +		if (other_req->r) {
  1.4352 +			/* The other request is still working; maybe it will
  1.4353 +			 * succeed. */
  1.4354 +			/* XXXX handle failure from set_timeout */
  1.4355 +			evdns_getaddrinfo_set_timeout(data->evdns_base, data);
  1.4356 +			data->pending_error = err;
  1.4357 +			return;
  1.4358 +		}
  1.4359 +
  1.4360 +		if (user_canceled) {
  1.4361 +			data->user_cb(EVUTIL_EAI_CANCEL, NULL, data->user_data);
  1.4362 +		} else if (data->pending_result) {
  1.4363 +			/* If we have an answer waiting, and we weren't
  1.4364 +			 * canceled, ignore this error. */
  1.4365 +			add_cname_to_reply(data, data->pending_result);
  1.4366 +			data->user_cb(0, data->pending_result, data->user_data);
  1.4367 +			data->pending_result = NULL;
  1.4368 +		} else {
  1.4369 +			if (data->pending_error)
  1.4370 +				err = getaddrinfo_merge_err(err,
  1.4371 +				    data->pending_error);
  1.4372 +			data->user_cb(err, NULL, data->user_data);
  1.4373 +		}
  1.4374 +		free_getaddrinfo_request(data);
  1.4375 +		return;
  1.4376 +	} else if (user_canceled) {
  1.4377 +		if (other_req->r) {
  1.4378 +			/* The other request is still working; let it hit this
  1.4379 +			 * callback with EVUTIL_EAI_CANCEL callback and report
  1.4380 +			 * the failure. */
  1.4381 +			return;
  1.4382 +		}
  1.4383 +		data->user_cb(EVUTIL_EAI_CANCEL, NULL, data->user_data);
  1.4384 +		free_getaddrinfo_request(data);
  1.4385 +		return;
  1.4386 +	}
  1.4387 +
  1.4388 +	/* Looks like we got some answers. We should turn them into addrinfos
  1.4389 +	 * and then either queue those or return them all. */
  1.4390 +	EVUTIL_ASSERT(type == DNS_IPv4_A || type == DNS_IPv6_AAAA);
  1.4391 +
  1.4392 +	if (type == DNS_IPv4_A) {
  1.4393 +		memset(&sin, 0, sizeof(sin));
  1.4394 +		sin.sin_family = AF_INET;
  1.4395 +		sin.sin_port = htons(data->port);
  1.4396 +
  1.4397 +		sa = (struct sockaddr *)&sin;
  1.4398 +		socklen = sizeof(sin);
  1.4399 +		addrlen = 4;
  1.4400 +		addrp = &sin.sin_addr.s_addr;
  1.4401 +	} else {
  1.4402 +		memset(&sin6, 0, sizeof(sin6));
  1.4403 +		sin6.sin6_family = AF_INET6;
  1.4404 +		sin6.sin6_port = htons(data->port);
  1.4405 +
  1.4406 +		sa = (struct sockaddr *)&sin6;
  1.4407 +		socklen = sizeof(sin6);
  1.4408 +		addrlen = 16;
  1.4409 +		addrp = &sin6.sin6_addr.s6_addr;
  1.4410 +	}
  1.4411 +
  1.4412 +	res = NULL;
  1.4413 +	for (i=0; i < count; ++i) {
  1.4414 +		struct evutil_addrinfo *ai;
  1.4415 +		memcpy(addrp, ((char*)addresses)+i*addrlen, addrlen);
  1.4416 +		ai = evutil_new_addrinfo(sa, socklen, &data->hints);
  1.4417 +		if (!ai) {
  1.4418 +			if (other_req->r) {
  1.4419 +				evdns_cancel_request(NULL, other_req->r);
  1.4420 +			}
  1.4421 +			data->user_cb(EVUTIL_EAI_MEMORY, NULL, data->user_data);
  1.4422 +			if (res)
  1.4423 +				evutil_freeaddrinfo(res);
  1.4424 +
  1.4425 +			if (other_req->r == NULL)
  1.4426 +				free_getaddrinfo_request(data);
  1.4427 +			return;
  1.4428 +		}
  1.4429 +		res = evutil_addrinfo_append(res, ai);
  1.4430 +	}
  1.4431 +
  1.4432 +	if (other_req->r) {
  1.4433 +		/* The other request is still in progress; wait for it */
  1.4434 +		/* XXXX handle failure from set_timeout */
  1.4435 +		evdns_getaddrinfo_set_timeout(data->evdns_base, data);
  1.4436 +		data->pending_result = res;
  1.4437 +		return;
  1.4438 +	} else {
  1.4439 +		/* The other request is done or never started; append its
  1.4440 +		 * results (if any) and return them. */
  1.4441 +		if (data->pending_result) {
  1.4442 +			if (req->type == DNS_IPv4_A)
  1.4443 +				res = evutil_addrinfo_append(res,
  1.4444 +				    data->pending_result);
  1.4445 +			else
  1.4446 +				res = evutil_addrinfo_append(
  1.4447 +				    data->pending_result, res);
  1.4448 +			data->pending_result = NULL;
  1.4449 +		}
  1.4450 +
  1.4451 +		/* Call the user callback. */
  1.4452 +		add_cname_to_reply(data, res);
  1.4453 +		data->user_cb(0, res, data->user_data);
  1.4454 +
  1.4455 +		/* Free data. */
  1.4456 +		free_getaddrinfo_request(data);
  1.4457 +	}
  1.4458 +}
  1.4459 +
  1.4460 +static struct hosts_entry *
  1.4461 +find_hosts_entry(struct evdns_base *base, const char *hostname,
  1.4462 +    struct hosts_entry *find_after)
  1.4463 +{
  1.4464 +	struct hosts_entry *e;
  1.4465 +
  1.4466 +	if (find_after)
  1.4467 +		e = TAILQ_NEXT(find_after, next);
  1.4468 +	else
  1.4469 +		e = TAILQ_FIRST(&base->hostsdb);
  1.4470 +
  1.4471 +	for (; e; e = TAILQ_NEXT(e, next)) {
  1.4472 +		if (!evutil_ascii_strcasecmp(e->hostname, hostname))
  1.4473 +			return e;
  1.4474 +	}
  1.4475 +	return NULL;
  1.4476 +}
  1.4477 +
  1.4478 +static int
  1.4479 +evdns_getaddrinfo_fromhosts(struct evdns_base *base,
  1.4480 +    const char *nodename, struct evutil_addrinfo *hints, ev_uint16_t port,
  1.4481 +    struct evutil_addrinfo **res)
  1.4482 +{
  1.4483 +	int n_found = 0;
  1.4484 +	struct hosts_entry *e;
  1.4485 +	struct evutil_addrinfo *ai=NULL;
  1.4486 +	int f = hints->ai_family;
  1.4487 +
  1.4488 +	EVDNS_LOCK(base);
  1.4489 +	for (e = find_hosts_entry(base, nodename, NULL); e;
  1.4490 +	    e = find_hosts_entry(base, nodename, e)) {
  1.4491 +		struct evutil_addrinfo *ai_new;
  1.4492 +		++n_found;
  1.4493 +		if ((e->addr.sa.sa_family == AF_INET && f == PF_INET6) ||
  1.4494 +		    (e->addr.sa.sa_family == AF_INET6 && f == PF_INET))
  1.4495 +			continue;
  1.4496 +		ai_new = evutil_new_addrinfo(&e->addr.sa, e->addrlen, hints);
  1.4497 +		if (!ai_new) {
  1.4498 +			n_found = 0;
  1.4499 +			goto out;
  1.4500 +		}
  1.4501 +		sockaddr_setport(ai_new->ai_addr, port);
  1.4502 +		ai = evutil_addrinfo_append(ai, ai_new);
  1.4503 +	}
  1.4504 +	EVDNS_UNLOCK(base);
  1.4505 +out:
  1.4506 +	if (n_found) {
  1.4507 +		/* Note that we return an empty answer if we found entries for
  1.4508 +		 * this hostname but none were of the right address type. */
  1.4509 +		*res = ai;
  1.4510 +		return 0;
  1.4511 +	} else {
  1.4512 +		if (ai)
  1.4513 +			evutil_freeaddrinfo(ai);
  1.4514 +		return -1;
  1.4515 +	}
  1.4516 +}
  1.4517 +
  1.4518 +struct evdns_getaddrinfo_request *
  1.4519 +evdns_getaddrinfo(struct evdns_base *dns_base,
  1.4520 +    const char *nodename, const char *servname,
  1.4521 +    const struct evutil_addrinfo *hints_in,
  1.4522 +    evdns_getaddrinfo_cb cb, void *arg)
  1.4523 +{
  1.4524 +	struct evdns_getaddrinfo_request *data;
  1.4525 +	struct evutil_addrinfo hints;
  1.4526 +	struct evutil_addrinfo *res = NULL;
  1.4527 +	int err;
  1.4528 +	int port = 0;
  1.4529 +	int want_cname = 0;
  1.4530 +
  1.4531 +	if (!dns_base) {
  1.4532 +		dns_base = current_base;
  1.4533 +		if (!dns_base) {
  1.4534 +			log(EVDNS_LOG_WARN,
  1.4535 +			    "Call to getaddrinfo_async with no "
  1.4536 +			    "evdns_base configured.");
  1.4537 +			cb(EVUTIL_EAI_FAIL, NULL, arg); /* ??? better error? */
  1.4538 +			return NULL;
  1.4539 +		}
  1.4540 +	}
  1.4541 +
  1.4542 +	/* If we _must_ answer this immediately, do so. */
  1.4543 +	if ((hints_in && (hints_in->ai_flags & EVUTIL_AI_NUMERICHOST))) {
  1.4544 +		res = NULL;
  1.4545 +		err = evutil_getaddrinfo(nodename, servname, hints_in, &res);
  1.4546 +		cb(err, res, arg);
  1.4547 +		return NULL;
  1.4548 +	}
  1.4549 +
  1.4550 +	if (hints_in) {
  1.4551 +		memcpy(&hints, hints_in, sizeof(hints));
  1.4552 +	} else {
  1.4553 +		memset(&hints, 0, sizeof(hints));
  1.4554 +		hints.ai_family = PF_UNSPEC;
  1.4555 +	}
  1.4556 +
  1.4557 +	evutil_adjust_hints_for_addrconfig(&hints);
  1.4558 +
  1.4559 +	/* Now try to see if we _can_ answer immediately. */
  1.4560 +	/* (It would be nice to do this by calling getaddrinfo directly, with
  1.4561 +	 * AI_NUMERICHOST, on plaforms that have it, but we can't: there isn't
  1.4562 +	 * a reliable way to distinguish the "that wasn't a numeric host!" case
  1.4563 +	 * from any other EAI_NONAME cases.) */
  1.4564 +	err = evutil_getaddrinfo_common(nodename, servname, &hints, &res, &port);
  1.4565 +	if (err != EVUTIL_EAI_NEED_RESOLVE) {
  1.4566 +		cb(err, res, arg);
  1.4567 +		return NULL;
  1.4568 +	}
  1.4569 +
  1.4570 +	/* If there is an entry in the hosts file, we should give it now. */
  1.4571 +	if (!evdns_getaddrinfo_fromhosts(dns_base, nodename, &hints, port, &res)) {
  1.4572 +		cb(0, res, arg);
  1.4573 +		return NULL;
  1.4574 +	}
  1.4575 +
  1.4576 +	/* Okay, things are serious now. We're going to need to actually
  1.4577 +	 * launch a request.
  1.4578 +	 */
  1.4579 +	data = mm_calloc(1,sizeof(struct evdns_getaddrinfo_request));
  1.4580 +	if (!data) {
  1.4581 +		cb(EVUTIL_EAI_MEMORY, NULL, arg);
  1.4582 +		return NULL;
  1.4583 +	}
  1.4584 +
  1.4585 +	memcpy(&data->hints, &hints, sizeof(data->hints));
  1.4586 +	data->port = (ev_uint16_t)port;
  1.4587 +	data->ipv4_request.type = DNS_IPv4_A;
  1.4588 +	data->ipv6_request.type = DNS_IPv6_AAAA;
  1.4589 +	data->user_cb = cb;
  1.4590 +	data->user_data = arg;
  1.4591 +	data->evdns_base = dns_base;
  1.4592 +
  1.4593 +	want_cname = (hints.ai_flags & EVUTIL_AI_CANONNAME);
  1.4594 +
  1.4595 +	/* If we are asked for a PF_UNSPEC address, we launch two requests in
  1.4596 +	 * parallel: one for an A address and one for an AAAA address.  We
  1.4597 +	 * can't send just one request, since many servers only answer one
  1.4598 +	 * question per DNS request.
  1.4599 +	 *
  1.4600 +	 * Once we have the answer to one request, we allow for a short
  1.4601 +	 * timeout before we report it, to see if the other one arrives.  If
  1.4602 +	 * they both show up in time, then we report both the answers.
  1.4603 +	 *
  1.4604 +	 * If too many addresses of one type time out or fail, we should stop
  1.4605 +	 * launching those requests. (XXX we don't do that yet.)
  1.4606 +	 */
  1.4607 +
  1.4608 +	if (hints.ai_family != PF_INET6) {
  1.4609 +		log(EVDNS_LOG_DEBUG, "Sending request for %s on ipv4 as %p",
  1.4610 +		    nodename, &data->ipv4_request);
  1.4611 +
  1.4612 +		data->ipv4_request.r = evdns_base_resolve_ipv4(dns_base,
  1.4613 +		    nodename, 0, evdns_getaddrinfo_gotresolve,
  1.4614 +		    &data->ipv4_request);
  1.4615 +		if (want_cname)
  1.4616 +			data->ipv4_request.r->current_req->put_cname_in_ptr =
  1.4617 +			    &data->cname_result;
  1.4618 +	}
  1.4619 +	if (hints.ai_family != PF_INET) {
  1.4620 +		log(EVDNS_LOG_DEBUG, "Sending request for %s on ipv6 as %p",
  1.4621 +		    nodename, &data->ipv6_request);
  1.4622 +
  1.4623 +		data->ipv6_request.r = evdns_base_resolve_ipv6(dns_base,
  1.4624 +		    nodename, 0, evdns_getaddrinfo_gotresolve,
  1.4625 +		    &data->ipv6_request);
  1.4626 +		if (want_cname)
  1.4627 +			data->ipv6_request.r->current_req->put_cname_in_ptr =
  1.4628 +			    &data->cname_result;
  1.4629 +	}
  1.4630 +
  1.4631 +	evtimer_assign(&data->timeout, dns_base->event_base,
  1.4632 +	    evdns_getaddrinfo_timeout_cb, data);
  1.4633 +
  1.4634 +	if (data->ipv4_request.r || data->ipv6_request.r) {
  1.4635 +		return data;
  1.4636 +	} else {
  1.4637 +		mm_free(data);
  1.4638 +		cb(EVUTIL_EAI_FAIL, NULL, arg);
  1.4639 +		return NULL;
  1.4640 +	}
  1.4641 +}
  1.4642 +
  1.4643 +void
  1.4644 +evdns_getaddrinfo_cancel(struct evdns_getaddrinfo_request *data)
  1.4645 +{
  1.4646 +	EVDNS_LOCK(data->evdns_base);
  1.4647 +	if (data->request_done) {
  1.4648 +		EVDNS_UNLOCK(data->evdns_base);
  1.4649 +		return;
  1.4650 +	}
  1.4651 +	event_del(&data->timeout);
  1.4652 +	data->user_canceled = 1;
  1.4653 +	if (data->ipv4_request.r)
  1.4654 +		evdns_cancel_request(data->evdns_base, data->ipv4_request.r);
  1.4655 +	if (data->ipv6_request.r)
  1.4656 +		evdns_cancel_request(data->evdns_base, data->ipv6_request.r);
  1.4657 +	EVDNS_UNLOCK(data->evdns_base);
  1.4658 +}

mercurial