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