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