Annotation of embedaddon/libevent/evdns.c, revision 1.1
1.1 ! misho 1: /* $Id: evdns.c 6979 2006-08-04 18:31:13Z nickm $ */
! 2:
! 3: /* The original version of this module was written by Adam Langley; for
! 4: * a history of modifications, check out the subversion logs.
! 5: *
! 6: * When editing this module, try to keep it re-mergeable by Adam. Don't
! 7: * reformat the whitespace, add Tor dependencies, or so on.
! 8: *
! 9: * TODO:
! 10: * - Support IPv6 and PTR records.
! 11: * - Replace all externally visible magic numbers with #defined constants.
! 12: * - Write doccumentation for APIs of all external functions.
! 13: */
! 14:
! 15: /* Async DNS Library
! 16: * Adam Langley <agl@imperialviolet.org>
! 17: * http://www.imperialviolet.org/eventdns.html
! 18: * Public Domain code
! 19: *
! 20: * This software is Public Domain. To view a copy of the public domain dedication,
! 21: * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
! 22: * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
! 23: *
! 24: * I ask and expect, but do not require, that all derivative works contain an
! 25: * attribution similar to:
! 26: * Parts developed by Adam Langley <agl@imperialviolet.org>
! 27: *
! 28: * You may wish to replace the word "Parts" with something else depending on
! 29: * the amount of original code.
! 30: *
! 31: * (Derivative works does not include programs which link against, run or include
! 32: * the source verbatim in their source distributions)
! 33: *
! 34: * Version: 0.1b
! 35: */
! 36:
! 37: #include <sys/types.h>
! 38: #ifdef HAVE_CONFIG_H
! 39: #include "config.h"
! 40: #endif
! 41:
! 42: #ifdef DNS_USE_FTIME_FOR_ID
! 43: #include <sys/timeb.h>
! 44: #endif
! 45:
! 46: #ifndef DNS_USE_CPU_CLOCK_FOR_ID
! 47: #ifndef DNS_USE_GETTIMEOFDAY_FOR_ID
! 48: #ifndef DNS_USE_OPENSSL_FOR_ID
! 49: #ifndef DNS_USE_FTIME_FOR_ID
! 50: #error Must configure at least one id generation method.
! 51: #error Please see the documentation.
! 52: #endif
! 53: #endif
! 54: #endif
! 55: #endif
! 56:
! 57: /* #define _POSIX_C_SOURCE 200507 */
! 58: #define _GNU_SOURCE
! 59:
! 60: #ifdef DNS_USE_CPU_CLOCK_FOR_ID
! 61: #ifdef DNS_USE_OPENSSL_FOR_ID
! 62: #error Multiple id options selected
! 63: #endif
! 64: #ifdef DNS_USE_GETTIMEOFDAY_FOR_ID
! 65: #error Multiple id options selected
! 66: #endif
! 67: #include <time.h>
! 68: #endif
! 69:
! 70: #ifdef DNS_USE_OPENSSL_FOR_ID
! 71: #ifdef DNS_USE_GETTIMEOFDAY_FOR_ID
! 72: #error Multiple id options selected
! 73: #endif
! 74: #include <openssl/rand.h>
! 75: #endif
! 76:
! 77: #ifndef _FORTIFY_SOURCE
! 78: #define _FORTIFY_SOURCE 3
! 79: #endif
! 80:
! 81: #include <string.h>
! 82: #include <fcntl.h>
! 83: #ifdef HAVE_SYS_TIME_H
! 84: #include <sys/time.h>
! 85: #endif
! 86: #ifdef HAVE_STDINT_H
! 87: #include <stdint.h>
! 88: #endif
! 89: #include <stdlib.h>
! 90: #include <string.h>
! 91: #include <errno.h>
! 92: #include <assert.h>
! 93: #ifdef HAVE_UNISTD_H
! 94: #include <unistd.h>
! 95: #endif
! 96: #include <limits.h>
! 97: #include <sys/stat.h>
! 98: #include <ctype.h>
! 99: #include <stdio.h>
! 100: #include <stdarg.h>
! 101:
! 102: #include "evdns.h"
! 103: #include "evutil.h"
! 104: #include "log.h"
! 105: #ifdef WIN32
! 106: #include <winsock2.h>
! 107: #include <windows.h>
! 108: #include <iphlpapi.h>
! 109: #include <io.h>
! 110: #else
! 111: #include <sys/socket.h>
! 112: #include <netinet/in.h>
! 113: #include <arpa/inet.h>
! 114: #endif
! 115:
! 116: #ifdef HAVE_NETINET_IN6_H
! 117: #include <netinet/in6.h>
! 118: #endif
! 119:
! 120: #define EVDNS_LOG_DEBUG 0
! 121: #define EVDNS_LOG_WARN 1
! 122:
! 123: #ifndef HOST_NAME_MAX
! 124: #define HOST_NAME_MAX 255
! 125: #endif
! 126:
! 127: #include <stdio.h>
! 128:
! 129: #undef MIN
! 130: #define MIN(a,b) ((a)<(b)?(a):(b))
! 131:
! 132: #ifdef __USE_ISOC99B
! 133: /* libevent doesn't work without this */
! 134: typedef ev_uint8_t u_char;
! 135: typedef unsigned int uint;
! 136: #endif
! 137: #include <event.h>
! 138:
! 139: #define u64 ev_uint64_t
! 140: #define u32 ev_uint32_t
! 141: #define u16 ev_uint16_t
! 142: #define u8 ev_uint8_t
! 143:
! 144: #ifdef WIN32
! 145: #define open _open
! 146: #define read _read
! 147: #define close _close
! 148: #define strdup _strdup
! 149: #endif
! 150:
! 151: #define MAX_ADDRS 32 /* maximum number of addresses from a single packet */
! 152: /* which we bother recording */
! 153:
! 154: #define TYPE_A EVDNS_TYPE_A
! 155: #define TYPE_CNAME 5
! 156: #define TYPE_PTR EVDNS_TYPE_PTR
! 157: #define TYPE_AAAA EVDNS_TYPE_AAAA
! 158:
! 159: #define CLASS_INET EVDNS_CLASS_INET
! 160:
! 161: struct request {
! 162: u8 *request; /* the dns packet data */
! 163: unsigned int request_len;
! 164: int reissue_count;
! 165: int tx_count; /* the number of times that this packet has been sent */
! 166: unsigned int request_type; /* TYPE_PTR or TYPE_A */
! 167: void *user_pointer; /* the pointer given to us for this request */
! 168: evdns_callback_type user_callback;
! 169: struct nameserver *ns; /* the server which we last sent it */
! 170:
! 171: /* elements used by the searching code */
! 172: int search_index;
! 173: struct search_state *search_state;
! 174: char *search_origname; /* needs to be free()ed */
! 175: int search_flags;
! 176:
! 177: /* these objects are kept in a circular list */
! 178: struct request *next, *prev;
! 179:
! 180: struct event timeout_event;
! 181:
! 182: u16 trans_id; /* the transaction id */
! 183: char request_appended; /* true if the request pointer is data which follows this struct */
! 184: char transmit_me; /* needs to be transmitted */
! 185: };
! 186:
! 187: #ifndef HAVE_STRUCT_IN6_ADDR
! 188: struct in6_addr {
! 189: u8 s6_addr[16];
! 190: };
! 191: #endif
! 192:
! 193: struct reply {
! 194: unsigned int type;
! 195: unsigned int have_answer;
! 196: union {
! 197: struct {
! 198: u32 addrcount;
! 199: u32 addresses[MAX_ADDRS];
! 200: } a;
! 201: struct {
! 202: u32 addrcount;
! 203: struct in6_addr addresses[MAX_ADDRS];
! 204: } aaaa;
! 205: struct {
! 206: char name[HOST_NAME_MAX];
! 207: } ptr;
! 208: } data;
! 209: };
! 210:
! 211: struct nameserver {
! 212: int socket; /* a connected UDP socket */
! 213: u32 address;
! 214: u16 port;
! 215: int failed_times; /* number of times which we have given this server a chance */
! 216: int timedout; /* number of times in a row a request has timed out */
! 217: struct event event;
! 218: /* these objects are kept in a circular list */
! 219: struct nameserver *next, *prev;
! 220: struct event timeout_event; /* used to keep the timeout for */
! 221: /* when we next probe this server. */
! 222: /* Valid if state == 0 */
! 223: char state; /* zero if we think that this server is down */
! 224: char choked; /* true if we have an EAGAIN from this server's socket */
! 225: char write_waiting; /* true if we are waiting for EV_WRITE events */
! 226: };
! 227:
! 228: static struct request *req_head = NULL, *req_waiting_head = NULL;
! 229: static struct nameserver *server_head = NULL;
! 230:
! 231: /* Represents a local port where we're listening for DNS requests. Right now, */
! 232: /* only UDP is supported. */
! 233: struct evdns_server_port {
! 234: int socket; /* socket we use to read queries and write replies. */
! 235: int refcnt; /* reference count. */
! 236: char choked; /* Are we currently blocked from writing? */
! 237: char closing; /* Are we trying to close this port, pending writes? */
! 238: evdns_request_callback_fn_type user_callback; /* Fn to handle requests */
! 239: void *user_data; /* Opaque pointer passed to user_callback */
! 240: struct event event; /* Read/write event */
! 241: /* circular list of replies that we want to write. */
! 242: struct server_request *pending_replies;
! 243: };
! 244:
! 245: /* Represents part of a reply being built. (That is, a single RR.) */
! 246: struct server_reply_item {
! 247: struct server_reply_item *next; /* next item in sequence. */
! 248: char *name; /* name part of the RR */
! 249: u16 type : 16; /* The RR type */
! 250: u16 class : 16; /* The RR class (usually CLASS_INET) */
! 251: u32 ttl; /* The RR TTL */
! 252: char is_name; /* True iff data is a label */
! 253: u16 datalen; /* Length of data; -1 if data is a label */
! 254: void *data; /* The contents of the RR */
! 255: };
! 256:
! 257: /* Represents a request that we've received as a DNS server, and holds */
! 258: /* the components of the reply as we're constructing it. */
! 259: struct server_request {
! 260: /* Pointers to the next and previous entries on the list of replies */
! 261: /* that we're waiting to write. Only set if we have tried to respond */
! 262: /* and gotten EAGAIN. */
! 263: struct server_request *next_pending;
! 264: struct server_request *prev_pending;
! 265:
! 266: u16 trans_id; /* Transaction id. */
! 267: struct evdns_server_port *port; /* Which port received this request on? */
! 268: struct sockaddr_storage addr; /* Where to send the response */
! 269: socklen_t addrlen; /* length of addr */
! 270:
! 271: int n_answer; /* how many answer RRs have been set? */
! 272: int n_authority; /* how many authority RRs have been set? */
! 273: int n_additional; /* how many additional RRs have been set? */
! 274:
! 275: struct server_reply_item *answer; /* linked list of answer RRs */
! 276: struct server_reply_item *authority; /* linked list of authority RRs */
! 277: struct server_reply_item *additional; /* linked list of additional RRs */
! 278:
! 279: /* Constructed response. Only set once we're ready to send a reply. */
! 280: /* Once this is set, the RR fields are cleared, and no more should be set. */
! 281: char *response;
! 282: size_t response_len;
! 283:
! 284: /* Caller-visible fields: flags, questions. */
! 285: struct evdns_server_request base;
! 286: };
! 287:
! 288: /* helper macro */
! 289: #define OFFSET_OF(st, member) ((off_t) (((char*)&((st*)0)->member)-(char*)0))
! 290:
! 291: /* Given a pointer to an evdns_server_request, get the corresponding */
! 292: /* server_request. */
! 293: #define TO_SERVER_REQUEST(base_ptr) \
! 294: ((struct server_request*) \
! 295: (((char*)(base_ptr) - OFFSET_OF(struct server_request, base))))
! 296:
! 297: /* The number of good nameservers that we have */
! 298: static int global_good_nameservers = 0;
! 299:
! 300: /* inflight requests are contained in the req_head list */
! 301: /* and are actually going out across the network */
! 302: static int global_requests_inflight = 0;
! 303: /* requests which aren't inflight are in the waiting list */
! 304: /* and are counted here */
! 305: static int global_requests_waiting = 0;
! 306:
! 307: static int global_max_requests_inflight = 64;
! 308:
! 309: static struct timeval global_timeout = {5, 0}; /* 5 seconds */
! 310: static int global_max_reissues = 1; /* a reissue occurs when we get some errors from the server */
! 311: static int global_max_retransmits = 3; /* number of times we'll retransmit a request which timed out */
! 312: /* number of timeouts in a row before we consider this server to be down */
! 313: static int global_max_nameserver_timeout = 3;
! 314:
! 315: /* These are the timeout values for nameservers. If we find a nameserver is down */
! 316: /* we try to probe it at intervals as given below. Values are in seconds. */
! 317: static const struct timeval global_nameserver_timeouts[] = {{10, 0}, {60, 0}, {300, 0}, {900, 0}, {3600, 0}};
! 318: static const int global_nameserver_timeouts_length = sizeof(global_nameserver_timeouts)/sizeof(struct timeval);
! 319:
! 320: static struct nameserver *nameserver_pick(void);
! 321: static void evdns_request_insert(struct request *req, struct request **head);
! 322: static void nameserver_ready_callback(int fd, short events, void *arg);
! 323: static int evdns_transmit(void);
! 324: static int evdns_request_transmit(struct request *req);
! 325: static void nameserver_send_probe(struct nameserver *const ns);
! 326: static void search_request_finished(struct request *const);
! 327: static int search_try_next(struct request *const req);
! 328: static int search_request_new(int type, const char *const name, int flags, evdns_callback_type user_callback, void *user_arg);
! 329: static void evdns_requests_pump_waiting_queue(void);
! 330: static u16 transaction_id_pick(void);
! 331: static struct request *request_new(int type, const char *name, int flags, evdns_callback_type callback, void *ptr);
! 332: static void request_submit(struct request *const req);
! 333:
! 334: static int server_request_free(struct server_request *req);
! 335: static void server_request_free_answers(struct server_request *req);
! 336: static void server_port_free(struct evdns_server_port *port);
! 337: static void server_port_ready_callback(int fd, short events, void *arg);
! 338:
! 339: static int strtoint(const char *const str);
! 340:
! 341: #ifdef WIN32
! 342: static int
! 343: last_error(int sock)
! 344: {
! 345: int optval, optvallen=sizeof(optval);
! 346: int err = WSAGetLastError();
! 347: if (err == WSAEWOULDBLOCK && sock >= 0) {
! 348: if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)&optval,
! 349: &optvallen))
! 350: return err;
! 351: if (optval)
! 352: return optval;
! 353: }
! 354: return err;
! 355:
! 356: }
! 357: static int
! 358: error_is_eagain(int err)
! 359: {
! 360: return err == EAGAIN || err == WSAEWOULDBLOCK;
! 361: }
! 362: static int
! 363: inet_aton(const char *c, struct in_addr *addr)
! 364: {
! 365: ev_uint32_t r;
! 366: if (strcmp(c, "255.255.255.255") == 0) {
! 367: addr->s_addr = 0xffffffffu;
! 368: } else {
! 369: r = inet_addr(c);
! 370: if (r == INADDR_NONE)
! 371: return 0;
! 372: addr->s_addr = r;
! 373: }
! 374: return 1;
! 375: }
! 376: #else
! 377: #define last_error(sock) (errno)
! 378: #define error_is_eagain(err) ((err) == EAGAIN)
! 379: #endif
! 380: #define CLOSE_SOCKET(s) EVUTIL_CLOSESOCKET(s)
! 381:
! 382: #define ISSPACE(c) isspace((int)(unsigned char)(c))
! 383: #define ISDIGIT(c) isdigit((int)(unsigned char)(c))
! 384:
! 385: static const char *
! 386: debug_ntoa(u32 address)
! 387: {
! 388: static char buf[32];
! 389: u32 a = ntohl(address);
! 390: evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d",
! 391: (int)(u8)((a>>24)&0xff),
! 392: (int)(u8)((a>>16)&0xff),
! 393: (int)(u8)((a>>8 )&0xff),
! 394: (int)(u8)((a )&0xff));
! 395: return buf;
! 396: }
! 397:
! 398: static evdns_debug_log_fn_type evdns_log_fn = NULL;
! 399:
! 400: void
! 401: evdns_set_log_fn(evdns_debug_log_fn_type fn)
! 402: {
! 403: evdns_log_fn = fn;
! 404: }
! 405:
! 406: #ifdef __GNUC__
! 407: #define EVDNS_LOG_CHECK __attribute__ ((format(printf, 2, 3)))
! 408: #else
! 409: #define EVDNS_LOG_CHECK
! 410: #endif
! 411:
! 412: static void _evdns_log(int warn, const char *fmt, ...) EVDNS_LOG_CHECK;
! 413: static void
! 414: _evdns_log(int warn, const char *fmt, ...)
! 415: {
! 416: va_list args;
! 417: static char buf[512];
! 418: if (!evdns_log_fn)
! 419: return;
! 420: va_start(args,fmt);
! 421: evutil_vsnprintf(buf, sizeof(buf), fmt, args);
! 422: buf[sizeof(buf)-1] = '\0';
! 423: evdns_log_fn(warn, buf);
! 424: va_end(args);
! 425: }
! 426:
! 427: #define log _evdns_log
! 428:
! 429: /* This walks the list of inflight requests to find the */
! 430: /* one with a matching transaction id. Returns NULL on */
! 431: /* failure */
! 432: static struct request *
! 433: request_find_from_trans_id(u16 trans_id) {
! 434: struct request *req = req_head, *const started_at = req_head;
! 435:
! 436: if (req) {
! 437: do {
! 438: if (req->trans_id == trans_id) return req;
! 439: req = req->next;
! 440: } while (req != started_at);
! 441: }
! 442:
! 443: return NULL;
! 444: }
! 445:
! 446: /* a libevent callback function which is called when a nameserver */
! 447: /* has gone down and we want to test if it has came back to life yet */
! 448: static void
! 449: nameserver_prod_callback(int fd, short events, void *arg) {
! 450: struct nameserver *const ns = (struct nameserver *) arg;
! 451: (void)fd;
! 452: (void)events;
! 453:
! 454: nameserver_send_probe(ns);
! 455: }
! 456:
! 457: /* a libevent callback which is called when a nameserver probe (to see if */
! 458: /* it has come back to life) times out. We increment the count of failed_times */
! 459: /* and wait longer to send the next probe packet. */
! 460: static void
! 461: nameserver_probe_failed(struct nameserver *const ns) {
! 462: const struct timeval * timeout;
! 463: (void) evtimer_del(&ns->timeout_event);
! 464: if (ns->state == 1) {
! 465: /* This can happen if the nameserver acts in a way which makes us mark */
! 466: /* it as bad and then starts sending good replies. */
! 467: return;
! 468: }
! 469:
! 470: timeout =
! 471: &global_nameserver_timeouts[MIN(ns->failed_times,
! 472: global_nameserver_timeouts_length - 1)];
! 473: ns->failed_times++;
! 474:
! 475: if (evtimer_add(&ns->timeout_event, (struct timeval *) timeout) < 0) {
! 476: log(EVDNS_LOG_WARN,
! 477: "Error from libevent when adding timer event for %s",
! 478: debug_ntoa(ns->address));
! 479: /* ???? Do more? */
! 480: }
! 481: }
! 482:
! 483: /* called when a nameserver has been deemed to have failed. For example, too */
! 484: /* many packets have timed out etc */
! 485: static void
! 486: nameserver_failed(struct nameserver *const ns, const char *msg) {
! 487: struct request *req, *started_at;
! 488: /* if this nameserver has already been marked as failed */
! 489: /* then don't do anything */
! 490: if (!ns->state) return;
! 491:
! 492: log(EVDNS_LOG_WARN, "Nameserver %s has failed: %s",
! 493: debug_ntoa(ns->address), msg);
! 494: global_good_nameservers--;
! 495: assert(global_good_nameservers >= 0);
! 496: if (global_good_nameservers == 0) {
! 497: log(EVDNS_LOG_WARN, "All nameservers have failed");
! 498: }
! 499:
! 500: ns->state = 0;
! 501: ns->failed_times = 1;
! 502:
! 503: if (evtimer_add(&ns->timeout_event, (struct timeval *) &global_nameserver_timeouts[0]) < 0) {
! 504: log(EVDNS_LOG_WARN,
! 505: "Error from libevent when adding timer event for %s",
! 506: debug_ntoa(ns->address));
! 507: /* ???? Do more? */
! 508: }
! 509:
! 510: /* walk the list of inflight requests to see if any can be reassigned to */
! 511: /* a different server. Requests in the waiting queue don't have a */
! 512: /* nameserver assigned yet */
! 513:
! 514: /* if we don't have *any* good nameservers then there's no point */
! 515: /* trying to reassign requests to one */
! 516: if (!global_good_nameservers) return;
! 517:
! 518: req = req_head;
! 519: started_at = req_head;
! 520: if (req) {
! 521: do {
! 522: if (req->tx_count == 0 && req->ns == ns) {
! 523: /* still waiting to go out, can be moved */
! 524: /* to another server */
! 525: req->ns = nameserver_pick();
! 526: }
! 527: req = req->next;
! 528: } while (req != started_at);
! 529: }
! 530: }
! 531:
! 532: static void
! 533: nameserver_up(struct nameserver *const ns) {
! 534: if (ns->state) return;
! 535: log(EVDNS_LOG_WARN, "Nameserver %s is back up",
! 536: debug_ntoa(ns->address));
! 537: evtimer_del(&ns->timeout_event);
! 538: ns->state = 1;
! 539: ns->failed_times = 0;
! 540: ns->timedout = 0;
! 541: global_good_nameservers++;
! 542: }
! 543:
! 544: static void
! 545: request_trans_id_set(struct request *const req, const u16 trans_id) {
! 546: req->trans_id = trans_id;
! 547: *((u16 *) req->request) = htons(trans_id);
! 548: }
! 549:
! 550: /* Called to remove a request from a list and dealloc it. */
! 551: /* head is a pointer to the head of the list it should be */
! 552: /* removed from or NULL if the request isn't in a list. */
! 553: static void
! 554: request_finished(struct request *const req, struct request **head) {
! 555: if (head) {
! 556: if (req->next == req) {
! 557: /* only item in the list */
! 558: *head = NULL;
! 559: } else {
! 560: req->next->prev = req->prev;
! 561: req->prev->next = req->next;
! 562: if (*head == req) *head = req->next;
! 563: }
! 564: }
! 565:
! 566: log(EVDNS_LOG_DEBUG, "Removing timeout for request %lx",
! 567: (unsigned long) req);
! 568: evtimer_del(&req->timeout_event);
! 569:
! 570: search_request_finished(req);
! 571: global_requests_inflight--;
! 572:
! 573: if (!req->request_appended) {
! 574: /* need to free the request data on it's own */
! 575: free(req->request);
! 576: } else {
! 577: /* the request data is appended onto the header */
! 578: /* so everything gets free()ed when we: */
! 579: }
! 580:
! 581: free(req);
! 582:
! 583: evdns_requests_pump_waiting_queue();
! 584: }
! 585:
! 586: /* This is called when a server returns a funny error code. */
! 587: /* We try the request again with another server. */
! 588: /* */
! 589: /* return: */
! 590: /* 0 ok */
! 591: /* 1 failed/reissue is pointless */
! 592: static int
! 593: request_reissue(struct request *req) {
! 594: const struct nameserver *const last_ns = req->ns;
! 595: /* the last nameserver should have been marked as failing */
! 596: /* by the caller of this function, therefore pick will try */
! 597: /* not to return it */
! 598: req->ns = nameserver_pick();
! 599: if (req->ns == last_ns) {
! 600: /* ... but pick did return it */
! 601: /* not a lot of point in trying again with the */
! 602: /* same server */
! 603: return 1;
! 604: }
! 605:
! 606: req->reissue_count++;
! 607: req->tx_count = 0;
! 608: req->transmit_me = 1;
! 609:
! 610: return 0;
! 611: }
! 612:
! 613: /* this function looks for space on the inflight queue and promotes */
! 614: /* requests from the waiting queue if it can. */
! 615: static void
! 616: evdns_requests_pump_waiting_queue(void) {
! 617: while (global_requests_inflight < global_max_requests_inflight &&
! 618: global_requests_waiting) {
! 619: struct request *req;
! 620: /* move a request from the waiting queue to the inflight queue */
! 621: assert(req_waiting_head);
! 622: if (req_waiting_head->next == req_waiting_head) {
! 623: /* only one item in the queue */
! 624: req = req_waiting_head;
! 625: req_waiting_head = NULL;
! 626: } else {
! 627: req = req_waiting_head;
! 628: req->next->prev = req->prev;
! 629: req->prev->next = req->next;
! 630: req_waiting_head = req->next;
! 631: }
! 632:
! 633: global_requests_waiting--;
! 634: global_requests_inflight++;
! 635:
! 636: req->ns = nameserver_pick();
! 637: request_trans_id_set(req, transaction_id_pick());
! 638:
! 639: evdns_request_insert(req, &req_head);
! 640: evdns_request_transmit(req);
! 641: evdns_transmit();
! 642: }
! 643: }
! 644:
! 645: static void
! 646: reply_callback(struct request *const req, u32 ttl, u32 err, struct reply *reply) {
! 647: switch (req->request_type) {
! 648: case TYPE_A:
! 649: if (reply)
! 650: req->user_callback(DNS_ERR_NONE, DNS_IPv4_A,
! 651: reply->data.a.addrcount, ttl,
! 652: reply->data.a.addresses,
! 653: req->user_pointer);
! 654: else
! 655: req->user_callback(err, 0, 0, 0, NULL, req->user_pointer);
! 656: return;
! 657: case TYPE_PTR:
! 658: if (reply) {
! 659: char *name = reply->data.ptr.name;
! 660: req->user_callback(DNS_ERR_NONE, DNS_PTR, 1, ttl,
! 661: &name, req->user_pointer);
! 662: } else {
! 663: req->user_callback(err, 0, 0, 0, NULL,
! 664: req->user_pointer);
! 665: }
! 666: return;
! 667: case TYPE_AAAA:
! 668: if (reply)
! 669: req->user_callback(DNS_ERR_NONE, DNS_IPv6_AAAA,
! 670: reply->data.aaaa.addrcount, ttl,
! 671: reply->data.aaaa.addresses,
! 672: req->user_pointer);
! 673: else
! 674: req->user_callback(err, 0, 0, 0, NULL, req->user_pointer);
! 675: return;
! 676: }
! 677: assert(0);
! 678: }
! 679:
! 680: /* this processes a parsed reply packet */
! 681: static void
! 682: reply_handle(struct request *const req, u16 flags, u32 ttl, struct reply *reply) {
! 683: int error;
! 684: static const int error_codes[] = {
! 685: DNS_ERR_FORMAT, DNS_ERR_SERVERFAILED, DNS_ERR_NOTEXIST,
! 686: DNS_ERR_NOTIMPL, DNS_ERR_REFUSED
! 687: };
! 688:
! 689: if (flags & 0x020f || !reply || !reply->have_answer) {
! 690: /* there was an error */
! 691: if (flags & 0x0200) {
! 692: error = DNS_ERR_TRUNCATED;
! 693: } else {
! 694: u16 error_code = (flags & 0x000f) - 1;
! 695: if (error_code > 4) {
! 696: error = DNS_ERR_UNKNOWN;
! 697: } else {
! 698: error = error_codes[error_code];
! 699: }
! 700: }
! 701:
! 702: switch(error) {
! 703: case DNS_ERR_NOTIMPL:
! 704: case DNS_ERR_REFUSED:
! 705: /* we regard these errors as marking a bad nameserver */
! 706: if (req->reissue_count < global_max_reissues) {
! 707: char msg[64];
! 708: evutil_snprintf(msg, sizeof(msg),
! 709: "Bad response %d (%s)",
! 710: error, evdns_err_to_string(error));
! 711: nameserver_failed(req->ns, msg);
! 712: if (!request_reissue(req)) return;
! 713: }
! 714: break;
! 715: case DNS_ERR_SERVERFAILED:
! 716: /* rcode 2 (servfailed) sometimes means "we
! 717: * are broken" and sometimes (with some binds)
! 718: * means "that request was very confusing."
! 719: * Treat this as a timeout, not a failure.
! 720: */
! 721: log(EVDNS_LOG_DEBUG, "Got a SERVERFAILED from nameserver %s; "
! 722: "will allow the request to time out.",
! 723: debug_ntoa(req->ns->address));
! 724: break;
! 725: default:
! 726: /* we got a good reply from the nameserver */
! 727: nameserver_up(req->ns);
! 728: }
! 729:
! 730: if (req->search_state && req->request_type != TYPE_PTR) {
! 731: /* if we have a list of domains to search in,
! 732: * try the next one */
! 733: if (!search_try_next(req)) {
! 734: /* a new request was issued so this
! 735: * request is finished and */
! 736: /* the user callback will be made when
! 737: * that request (or a */
! 738: /* child of it) finishes. */
! 739: request_finished(req, &req_head);
! 740: return;
! 741: }
! 742: }
! 743:
! 744: /* all else failed. Pass the failure up */
! 745: reply_callback(req, 0, error, NULL);
! 746: request_finished(req, &req_head);
! 747: } else {
! 748: /* all ok, tell the user */
! 749: reply_callback(req, ttl, 0, reply);
! 750: nameserver_up(req->ns);
! 751: request_finished(req, &req_head);
! 752: }
! 753: }
! 754:
! 755: static int
! 756: name_parse(u8 *packet, int length, int *idx, char *name_out, int name_out_len) {
! 757: int name_end = -1;
! 758: int j = *idx;
! 759: int ptr_count = 0;
! 760: #define GET32(x) do { if (j + 4 > length) goto err; memcpy(&_t32, packet + j, 4); j += 4; x = ntohl(_t32); } while(0)
! 761: #define GET16(x) do { if (j + 2 > length) goto err; memcpy(&_t, packet + j, 2); j += 2; x = ntohs(_t); } while(0)
! 762: #define GET8(x) do { if (j >= length) goto err; x = packet[j++]; } while(0)
! 763:
! 764: char *cp = name_out;
! 765: const char *const end = name_out + name_out_len;
! 766:
! 767: /* Normally, names are a series of length prefixed strings terminated */
! 768: /* with a length of 0 (the lengths are u8's < 63). */
! 769: /* However, the length can start with a pair of 1 bits and that */
! 770: /* means that the next 14 bits are a pointer within the current */
! 771: /* packet. */
! 772:
! 773: for(;;) {
! 774: u8 label_len;
! 775: if (j >= length) return -1;
! 776: GET8(label_len);
! 777: if (!label_len) break;
! 778: if (label_len & 0xc0) {
! 779: u8 ptr_low;
! 780: GET8(ptr_low);
! 781: if (name_end < 0) name_end = j;
! 782: j = (((int)label_len & 0x3f) << 8) + ptr_low;
! 783: /* Make sure that the target offset is in-bounds. */
! 784: if (j < 0 || j >= length) return -1;
! 785: /* If we've jumped more times than there are characters in the
! 786: * message, we must have a loop. */
! 787: if (++ptr_count > length) return -1;
! 788: continue;
! 789: }
! 790: if (label_len > 63) return -1;
! 791: if (cp != name_out) {
! 792: if (cp + 1 >= end) return -1;
! 793: *cp++ = '.';
! 794: }
! 795: if (cp + label_len >= end) return -1;
! 796: memcpy(cp, packet + j, label_len);
! 797: cp += label_len;
! 798: j += label_len;
! 799: }
! 800: if (cp >= end) return -1;
! 801: *cp = '\0';
! 802: if (name_end < 0)
! 803: *idx = j;
! 804: else
! 805: *idx = name_end;
! 806: return 0;
! 807: err:
! 808: return -1;
! 809: }
! 810:
! 811: /* parses a raw request from a nameserver */
! 812: static int
! 813: reply_parse(u8 *packet, int length) {
! 814: int j = 0, k = 0; /* index into packet */
! 815: u16 _t; /* used by the macros */
! 816: u32 _t32; /* used by the macros */
! 817: char tmp_name[256], cmp_name[256]; /* used by the macros */
! 818:
! 819: u16 trans_id, questions, answers, authority, additional, datalength;
! 820: u16 flags = 0;
! 821: u32 ttl, ttl_r = 0xffffffff;
! 822: struct reply reply;
! 823: struct request *req = NULL;
! 824: unsigned int i;
! 825:
! 826: GET16(trans_id);
! 827: GET16(flags);
! 828: GET16(questions);
! 829: GET16(answers);
! 830: GET16(authority);
! 831: GET16(additional);
! 832: (void) authority; /* suppress "unused variable" warnings. */
! 833: (void) additional; /* suppress "unused variable" warnings. */
! 834:
! 835: req = request_find_from_trans_id(trans_id);
! 836: if (!req) return -1;
! 837:
! 838: memset(&reply, 0, sizeof(reply));
! 839:
! 840: /* If it's not an answer, it doesn't correspond to any request. */
! 841: if (!(flags & 0x8000)) return -1; /* must be an answer */
! 842: if (flags & 0x020f) {
! 843: /* there was an error */
! 844: goto err;
! 845: }
! 846: /* if (!answers) return; */ /* must have an answer of some form */
! 847:
! 848: /* This macro skips a name in the DNS reply. */
! 849: #define SKIP_NAME \
! 850: do { tmp_name[0] = '\0'; \
! 851: if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0)\
! 852: goto err; \
! 853: } while(0)
! 854: #define TEST_NAME \
! 855: do { tmp_name[0] = '\0'; \
! 856: cmp_name[0] = '\0'; \
! 857: k = j; \
! 858: if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0)\
! 859: goto err; \
! 860: if (name_parse(req->request, req->request_len, &k, cmp_name, sizeof(cmp_name))<0) \
! 861: goto err; \
! 862: if (memcmp(tmp_name, cmp_name, strlen (tmp_name)) != 0) \
! 863: return (-1); /* we ignore mismatching names */ \
! 864: } while(0)
! 865:
! 866: reply.type = req->request_type;
! 867:
! 868: /* skip over each question in the reply */
! 869: for (i = 0; i < questions; ++i) {
! 870: /* the question looks like
! 871: * <label:name><u16:type><u16:class>
! 872: */
! 873: TEST_NAME;
! 874: j += 4;
! 875: if (j > length) goto err;
! 876: }
! 877:
! 878: /* now we have the answer section which looks like
! 879: * <label:name><u16:type><u16:class><u32:ttl><u16:len><data...>
! 880: */
! 881:
! 882: for (i = 0; i < answers; ++i) {
! 883: u16 type, class;
! 884:
! 885: SKIP_NAME;
! 886: GET16(type);
! 887: GET16(class);
! 888: GET32(ttl);
! 889: GET16(datalength);
! 890:
! 891: if (type == TYPE_A && class == CLASS_INET) {
! 892: int addrcount, addrtocopy;
! 893: if (req->request_type != TYPE_A) {
! 894: j += datalength; continue;
! 895: }
! 896: if ((datalength & 3) != 0) /* not an even number of As. */
! 897: goto err;
! 898: addrcount = datalength >> 2;
! 899: addrtocopy = MIN(MAX_ADDRS - reply.data.a.addrcount, (unsigned)addrcount);
! 900:
! 901: ttl_r = MIN(ttl_r, ttl);
! 902: /* we only bother with the first four addresses. */
! 903: if (j + 4*addrtocopy > length) goto err;
! 904: memcpy(&reply.data.a.addresses[reply.data.a.addrcount],
! 905: packet + j, 4*addrtocopy);
! 906: j += 4*addrtocopy;
! 907: reply.data.a.addrcount += addrtocopy;
! 908: reply.have_answer = 1;
! 909: if (reply.data.a.addrcount == MAX_ADDRS) break;
! 910: } else if (type == TYPE_PTR && class == CLASS_INET) {
! 911: if (req->request_type != TYPE_PTR) {
! 912: j += datalength; continue;
! 913: }
! 914: if (name_parse(packet, length, &j, reply.data.ptr.name,
! 915: sizeof(reply.data.ptr.name))<0)
! 916: goto err;
! 917: ttl_r = MIN(ttl_r, ttl);
! 918: reply.have_answer = 1;
! 919: break;
! 920: } else if (type == TYPE_AAAA && class == CLASS_INET) {
! 921: int addrcount, addrtocopy;
! 922: if (req->request_type != TYPE_AAAA) {
! 923: j += datalength; continue;
! 924: }
! 925: if ((datalength & 15) != 0) /* not an even number of AAAAs. */
! 926: goto err;
! 927: addrcount = datalength >> 4; /* each address is 16 bytes long */
! 928: addrtocopy = MIN(MAX_ADDRS - reply.data.aaaa.addrcount, (unsigned)addrcount);
! 929: ttl_r = MIN(ttl_r, ttl);
! 930:
! 931: /* we only bother with the first four addresses. */
! 932: if (j + 16*addrtocopy > length) goto err;
! 933: memcpy(&reply.data.aaaa.addresses[reply.data.aaaa.addrcount],
! 934: packet + j, 16*addrtocopy);
! 935: reply.data.aaaa.addrcount += addrtocopy;
! 936: j += 16*addrtocopy;
! 937: reply.have_answer = 1;
! 938: if (reply.data.aaaa.addrcount == MAX_ADDRS) break;
! 939: } else {
! 940: /* skip over any other type of resource */
! 941: j += datalength;
! 942: }
! 943: }
! 944:
! 945: reply_handle(req, flags, ttl_r, &reply);
! 946: return 0;
! 947: err:
! 948: if (req)
! 949: reply_handle(req, flags, 0, NULL);
! 950: return -1;
! 951: }
! 952:
! 953: /* Parse a raw request (packet,length) sent to a nameserver port (port) from */
! 954: /* a DNS client (addr,addrlen), and if it's well-formed, call the corresponding */
! 955: /* callback. */
! 956: static int
! 957: request_parse(u8 *packet, int length, struct evdns_server_port *port, struct sockaddr *addr, socklen_t addrlen)
! 958: {
! 959: int j = 0; /* index into packet */
! 960: u16 _t; /* used by the macros */
! 961: char tmp_name[256]; /* used by the macros */
! 962:
! 963: int i;
! 964: u16 trans_id, flags, questions, answers, authority, additional;
! 965: struct server_request *server_req = NULL;
! 966:
! 967: /* Get the header fields */
! 968: GET16(trans_id);
! 969: GET16(flags);
! 970: GET16(questions);
! 971: GET16(answers);
! 972: GET16(authority);
! 973: GET16(additional);
! 974:
! 975: if (flags & 0x8000) return -1; /* Must not be an answer. */
! 976: flags &= 0x0110; /* Only RD and CD get preserved. */
! 977:
! 978: server_req = malloc(sizeof(struct server_request));
! 979: if (server_req == NULL) return -1;
! 980: memset(server_req, 0, sizeof(struct server_request));
! 981:
! 982: server_req->trans_id = trans_id;
! 983: memcpy(&server_req->addr, addr, addrlen);
! 984: server_req->addrlen = addrlen;
! 985:
! 986: server_req->base.flags = flags;
! 987: server_req->base.nquestions = 0;
! 988: server_req->base.questions = malloc(sizeof(struct evdns_server_question *) * questions);
! 989: if (server_req->base.questions == NULL)
! 990: goto err;
! 991:
! 992: for (i = 0; i < questions; ++i) {
! 993: u16 type, class;
! 994: struct evdns_server_question *q;
! 995: int namelen;
! 996: if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0)
! 997: goto err;
! 998: GET16(type);
! 999: GET16(class);
! 1000: namelen = strlen(tmp_name);
! 1001: q = malloc(sizeof(struct evdns_server_question) + namelen);
! 1002: if (!q)
! 1003: goto err;
! 1004: q->type = type;
! 1005: q->dns_question_class = class;
! 1006: memcpy(q->name, tmp_name, namelen+1);
! 1007: server_req->base.questions[server_req->base.nquestions++] = q;
! 1008: }
! 1009:
! 1010: /* Ignore answers, authority, and additional. */
! 1011:
! 1012: server_req->port = port;
! 1013: port->refcnt++;
! 1014:
! 1015: /* Only standard queries are supported. */
! 1016: if (flags & 0x7800) {
! 1017: evdns_server_request_respond(&(server_req->base), DNS_ERR_NOTIMPL);
! 1018: return -1;
! 1019: }
! 1020:
! 1021: port->user_callback(&(server_req->base), port->user_data);
! 1022:
! 1023: return 0;
! 1024: err:
! 1025: if (server_req) {
! 1026: if (server_req->base.questions) {
! 1027: for (i = 0; i < server_req->base.nquestions; ++i)
! 1028: free(server_req->base.questions[i]);
! 1029: free(server_req->base.questions);
! 1030: }
! 1031: free(server_req);
! 1032: }
! 1033: return -1;
! 1034:
! 1035: #undef SKIP_NAME
! 1036: #undef GET32
! 1037: #undef GET16
! 1038: #undef GET8
! 1039: }
! 1040:
! 1041: static u16
! 1042: default_transaction_id_fn(void)
! 1043: {
! 1044: u16 trans_id;
! 1045: #ifdef DNS_USE_CPU_CLOCK_FOR_ID
! 1046: struct timespec ts;
! 1047: static int clkid = -1;
! 1048: if (clkid == -1) {
! 1049: clkid = CLOCK_REALTIME;
! 1050: #ifdef CLOCK_MONOTONIC
! 1051: if (clock_gettime(CLOCK_MONOTONIC, &ts) != -1)
! 1052: clkid = CLOCK_MONOTONIC;
! 1053: #endif
! 1054: }
! 1055: if (clock_gettime(clkid, &ts) == -1)
! 1056: event_err(1, "clock_gettime");
! 1057: trans_id = ts.tv_nsec & 0xffff;
! 1058: #endif
! 1059:
! 1060: #ifdef DNS_USE_FTIME_FOR_ID
! 1061: struct _timeb tb;
! 1062: _ftime(&tb);
! 1063: trans_id = tb.millitm & 0xffff;
! 1064: #endif
! 1065:
! 1066: #ifdef DNS_USE_GETTIMEOFDAY_FOR_ID
! 1067: struct timeval tv;
! 1068: evutil_gettimeofday(&tv, NULL);
! 1069: trans_id = tv.tv_usec & 0xffff;
! 1070: #endif
! 1071:
! 1072: #ifdef DNS_USE_OPENSSL_FOR_ID
! 1073: if (RAND_pseudo_bytes((u8 *) &trans_id, 2) == -1) {
! 1074: /* in the case that the RAND call fails we back */
! 1075: /* down to using gettimeofday. */
! 1076: /*
! 1077: struct timeval tv;
! 1078: evutil_gettimeofday(&tv, NULL);
! 1079: trans_id = tv.tv_usec & 0xffff;
! 1080: */
! 1081: abort();
! 1082: }
! 1083: #endif
! 1084: return trans_id;
! 1085: }
! 1086:
! 1087: static ev_uint16_t (*trans_id_function)(void) = default_transaction_id_fn;
! 1088:
! 1089: void
! 1090: evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void))
! 1091: {
! 1092: if (fn)
! 1093: trans_id_function = fn;
! 1094: else
! 1095: trans_id_function = default_transaction_id_fn;
! 1096: }
! 1097:
! 1098: /* Try to choose a strong transaction id which isn't already in flight */
! 1099: static u16
! 1100: transaction_id_pick(void) {
! 1101: for (;;) {
! 1102: const struct request *req = req_head, *started_at;
! 1103: u16 trans_id = trans_id_function();
! 1104:
! 1105: if (trans_id == 0xffff) continue;
! 1106: /* now check to see if that id is already inflight */
! 1107: req = started_at = req_head;
! 1108: if (req) {
! 1109: do {
! 1110: if (req->trans_id == trans_id) break;
! 1111: req = req->next;
! 1112: } while (req != started_at);
! 1113: }
! 1114: /* we didn't find it, so this is a good id */
! 1115: if (req == started_at) return trans_id;
! 1116: }
! 1117: }
! 1118:
! 1119: /* choose a namesever to use. This function will try to ignore */
! 1120: /* nameservers which we think are down and load balance across the rest */
! 1121: /* by updating the server_head global each time. */
! 1122: static struct nameserver *
! 1123: nameserver_pick(void) {
! 1124: struct nameserver *started_at = server_head, *picked;
! 1125: if (!server_head) return NULL;
! 1126:
! 1127: /* if we don't have any good nameservers then there's no */
! 1128: /* point in trying to find one. */
! 1129: if (!global_good_nameservers) {
! 1130: server_head = server_head->next;
! 1131: return server_head;
! 1132: }
! 1133:
! 1134: /* remember that nameservers are in a circular list */
! 1135: for (;;) {
! 1136: if (server_head->state) {
! 1137: /* we think this server is currently good */
! 1138: picked = server_head;
! 1139: server_head = server_head->next;
! 1140: return picked;
! 1141: }
! 1142:
! 1143: server_head = server_head->next;
! 1144: if (server_head == started_at) {
! 1145: /* all the nameservers seem to be down */
! 1146: /* so we just return this one and hope for the */
! 1147: /* best */
! 1148: assert(global_good_nameservers == 0);
! 1149: picked = server_head;
! 1150: server_head = server_head->next;
! 1151: return picked;
! 1152: }
! 1153: }
! 1154: }
! 1155:
! 1156: static int
! 1157: address_is_correct(struct nameserver *ns, struct sockaddr *sa, socklen_t slen)
! 1158: {
! 1159: struct sockaddr_in *sin = (struct sockaddr_in*) sa;
! 1160: if (sa->sa_family != AF_INET || slen != sizeof(struct sockaddr_in))
! 1161: return 0;
! 1162: if (sin->sin_addr.s_addr != ns->address)
! 1163: return 0;
! 1164: return 1;
! 1165: }
! 1166:
! 1167: /* this is called when a namesever socket is ready for reading */
! 1168: static void
! 1169: nameserver_read(struct nameserver *ns) {
! 1170: u8 packet[1500];
! 1171: struct sockaddr_storage ss;
! 1172: socklen_t addrlen = sizeof(ss);
! 1173:
! 1174: for (;;) {
! 1175: const int r = recvfrom(ns->socket, packet, sizeof(packet), 0,
! 1176: (struct sockaddr*)&ss, &addrlen);
! 1177: if (r < 0) {
! 1178: int err = last_error(ns->socket);
! 1179: if (error_is_eagain(err)) return;
! 1180: nameserver_failed(ns, strerror(err));
! 1181: return;
! 1182: }
! 1183: if (!address_is_correct(ns, (struct sockaddr*)&ss, addrlen)) {
! 1184: log(EVDNS_LOG_WARN, "Address mismatch on received "
! 1185: "DNS packet.");
! 1186: return;
! 1187: }
! 1188: ns->timedout = 0;
! 1189: reply_parse(packet, r);
! 1190: }
! 1191: }
! 1192:
! 1193: /* Read a packet from a DNS client on a server port s, parse it, and */
! 1194: /* act accordingly. */
! 1195: static void
! 1196: server_port_read(struct evdns_server_port *s) {
! 1197: u8 packet[1500];
! 1198: struct sockaddr_storage addr;
! 1199: socklen_t addrlen;
! 1200: int r;
! 1201:
! 1202: for (;;) {
! 1203: addrlen = sizeof(struct sockaddr_storage);
! 1204: r = recvfrom(s->socket, packet, sizeof(packet), 0,
! 1205: (struct sockaddr*) &addr, &addrlen);
! 1206: if (r < 0) {
! 1207: int err = last_error(s->socket);
! 1208: if (error_is_eagain(err)) return;
! 1209: log(EVDNS_LOG_WARN, "Error %s (%d) while reading request.",
! 1210: strerror(err), err);
! 1211: return;
! 1212: }
! 1213: request_parse(packet, r, s, (struct sockaddr*) &addr, addrlen);
! 1214: }
! 1215: }
! 1216:
! 1217: /* Try to write all pending replies on a given DNS server port. */
! 1218: static void
! 1219: server_port_flush(struct evdns_server_port *port)
! 1220: {
! 1221: while (port->pending_replies) {
! 1222: struct server_request *req = port->pending_replies;
! 1223: int r = sendto(port->socket, req->response, req->response_len, 0,
! 1224: (struct sockaddr*) &req->addr, req->addrlen);
! 1225: if (r < 0) {
! 1226: int err = last_error(port->socket);
! 1227: if (error_is_eagain(err))
! 1228: return;
! 1229: log(EVDNS_LOG_WARN, "Error %s (%d) while writing response to port; dropping", strerror(err), err);
! 1230: }
! 1231: if (server_request_free(req)) {
! 1232: /* we released the last reference to req->port. */
! 1233: return;
! 1234: }
! 1235: }
! 1236:
! 1237: /* We have no more pending requests; stop listening for 'writeable' events. */
! 1238: (void) event_del(&port->event);
! 1239: event_set(&port->event, port->socket, EV_READ | EV_PERSIST,
! 1240: server_port_ready_callback, port);
! 1241: if (event_add(&port->event, NULL) < 0) {
! 1242: log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server.");
! 1243: /* ???? Do more? */
! 1244: }
! 1245: }
! 1246:
! 1247: /* set if we are waiting for the ability to write to this server. */
! 1248: /* if waiting is true then we ask libevent for EV_WRITE events, otherwise */
! 1249: /* we stop these events. */
! 1250: static void
! 1251: nameserver_write_waiting(struct nameserver *ns, char waiting) {
! 1252: if (ns->write_waiting == waiting) return;
! 1253:
! 1254: ns->write_waiting = waiting;
! 1255: (void) event_del(&ns->event);
! 1256: event_set(&ns->event, ns->socket, EV_READ | (waiting ? EV_WRITE : 0) | EV_PERSIST,
! 1257: nameserver_ready_callback, ns);
! 1258: if (event_add(&ns->event, NULL) < 0) {
! 1259: log(EVDNS_LOG_WARN, "Error from libevent when adding event for %s",
! 1260: debug_ntoa(ns->address));
! 1261: /* ???? Do more? */
! 1262: }
! 1263: }
! 1264:
! 1265: /* a callback function. Called by libevent when the kernel says that */
! 1266: /* a nameserver socket is ready for writing or reading */
! 1267: static void
! 1268: nameserver_ready_callback(int fd, short events, void *arg) {
! 1269: struct nameserver *ns = (struct nameserver *) arg;
! 1270: (void)fd;
! 1271:
! 1272: if (events & EV_WRITE) {
! 1273: ns->choked = 0;
! 1274: if (!evdns_transmit()) {
! 1275: nameserver_write_waiting(ns, 0);
! 1276: }
! 1277: }
! 1278: if (events & EV_READ) {
! 1279: nameserver_read(ns);
! 1280: }
! 1281: }
! 1282:
! 1283: /* a callback function. Called by libevent when the kernel says that */
! 1284: /* a server socket is ready for writing or reading. */
! 1285: static void
! 1286: server_port_ready_callback(int fd, short events, void *arg) {
! 1287: struct evdns_server_port *port = (struct evdns_server_port *) arg;
! 1288: (void) fd;
! 1289:
! 1290: if (events & EV_WRITE) {
! 1291: port->choked = 0;
! 1292: server_port_flush(port);
! 1293: }
! 1294: if (events & EV_READ) {
! 1295: server_port_read(port);
! 1296: }
! 1297: }
! 1298:
! 1299: /* This is an inefficient representation; only use it via the dnslabel_table_*
! 1300: * functions, so that is can be safely replaced with something smarter later. */
! 1301: #define MAX_LABELS 128
! 1302: /* Structures used to implement name compression */
! 1303: struct dnslabel_entry { char *v; off_t pos; };
! 1304: struct dnslabel_table {
! 1305: int n_labels; /* number of current entries */
! 1306: /* map from name to position in message */
! 1307: struct dnslabel_entry labels[MAX_LABELS];
! 1308: };
! 1309:
! 1310: /* Initialize dnslabel_table. */
! 1311: static void
! 1312: dnslabel_table_init(struct dnslabel_table *table)
! 1313: {
! 1314: table->n_labels = 0;
! 1315: }
! 1316:
! 1317: /* Free all storage held by table, but not the table itself. */
! 1318: static void
! 1319: dnslabel_clear(struct dnslabel_table *table)
! 1320: {
! 1321: int i;
! 1322: for (i = 0; i < table->n_labels; ++i)
! 1323: free(table->labels[i].v);
! 1324: table->n_labels = 0;
! 1325: }
! 1326:
! 1327: /* return the position of the label in the current message, or -1 if the label */
! 1328: /* hasn't been used yet. */
! 1329: static int
! 1330: dnslabel_table_get_pos(const struct dnslabel_table *table, const char *label)
! 1331: {
! 1332: int i;
! 1333: for (i = 0; i < table->n_labels; ++i) {
! 1334: if (!strcmp(label, table->labels[i].v))
! 1335: return table->labels[i].pos;
! 1336: }
! 1337: return -1;
! 1338: }
! 1339:
! 1340: /* remember that we've used the label at position pos */
! 1341: static int
! 1342: dnslabel_table_add(struct dnslabel_table *table, const char *label, off_t pos)
! 1343: {
! 1344: char *v;
! 1345: int p;
! 1346: if (table->n_labels == MAX_LABELS)
! 1347: return (-1);
! 1348: v = strdup(label);
! 1349: if (v == NULL)
! 1350: return (-1);
! 1351: p = table->n_labels++;
! 1352: table->labels[p].v = v;
! 1353: table->labels[p].pos = pos;
! 1354:
! 1355: return (0);
! 1356: }
! 1357:
! 1358: /* Converts a string to a length-prefixed set of DNS labels, starting */
! 1359: /* at buf[j]. name and buf must not overlap. name_len should be the length */
! 1360: /* of name. table is optional, and is used for compression. */
! 1361: /* */
! 1362: /* Input: abc.def */
! 1363: /* Output: <3>abc<3>def<0> */
! 1364: /* */
! 1365: /* Returns the first index after the encoded name, or negative on error. */
! 1366: /* -1 label was > 63 bytes */
! 1367: /* -2 name too long to fit in buffer. */
! 1368: /* */
! 1369: static off_t
! 1370: dnsname_to_labels(u8 *const buf, size_t buf_len, off_t j,
! 1371: const char *name, const int name_len,
! 1372: struct dnslabel_table *table) {
! 1373: const char *end = name + name_len;
! 1374: int ref = 0;
! 1375: u16 _t;
! 1376:
! 1377: #define APPEND16(x) do { \
! 1378: if (j + 2 > (off_t)buf_len) \
! 1379: goto overflow; \
! 1380: _t = htons(x); \
! 1381: memcpy(buf + j, &_t, 2); \
! 1382: j += 2; \
! 1383: } while (0)
! 1384: #define APPEND32(x) do { \
! 1385: if (j + 4 > (off_t)buf_len) \
! 1386: goto overflow; \
! 1387: _t32 = htonl(x); \
! 1388: memcpy(buf + j, &_t32, 4); \
! 1389: j += 4; \
! 1390: } while (0)
! 1391:
! 1392: if (name_len > 255) return -2;
! 1393:
! 1394: for (;;) {
! 1395: const char *const start = name;
! 1396: if (table && (ref = dnslabel_table_get_pos(table, name)) >= 0) {
! 1397: APPEND16(ref | 0xc000);
! 1398: return j;
! 1399: }
! 1400: name = strchr(name, '.');
! 1401: if (!name) {
! 1402: const unsigned int label_len = end - start;
! 1403: if (label_len > 63) return -1;
! 1404: if ((size_t)(j+label_len+1) > buf_len) return -2;
! 1405: if (table) dnslabel_table_add(table, start, j);
! 1406: buf[j++] = label_len;
! 1407:
! 1408: memcpy(buf + j, start, end - start);
! 1409: j += end - start;
! 1410: break;
! 1411: } else {
! 1412: /* append length of the label. */
! 1413: const unsigned int label_len = name - start;
! 1414: if (label_len > 63) return -1;
! 1415: if ((size_t)(j+label_len+1) > buf_len) return -2;
! 1416: if (table) dnslabel_table_add(table, start, j);
! 1417: buf[j++] = label_len;
! 1418:
! 1419: memcpy(buf + j, start, name - start);
! 1420: j += name - start;
! 1421: /* hop over the '.' */
! 1422: name++;
! 1423: }
! 1424: }
! 1425:
! 1426: /* the labels must be terminated by a 0. */
! 1427: /* It's possible that the name ended in a . */
! 1428: /* in which case the zero is already there */
! 1429: if (!j || buf[j-1]) buf[j++] = 0;
! 1430: return j;
! 1431: overflow:
! 1432: return (-2);
! 1433: }
! 1434:
! 1435: /* Finds the length of a dns request for a DNS name of the given */
! 1436: /* length. The actual request may be smaller than the value returned */
! 1437: /* here */
! 1438: static int
! 1439: evdns_request_len(const int name_len) {
! 1440: return 96 + /* length of the DNS standard header */
! 1441: name_len + 2 +
! 1442: 4; /* space for the resource type */
! 1443: }
! 1444:
! 1445: /* build a dns request packet into buf. buf should be at least as long */
! 1446: /* as evdns_request_len told you it should be. */
! 1447: /* */
! 1448: /* Returns the amount of space used. Negative on error. */
! 1449: static int
! 1450: evdns_request_data_build(const char *const name, const int name_len,
! 1451: const u16 trans_id, const u16 type, const u16 class,
! 1452: u8 *const buf, size_t buf_len) {
! 1453: off_t j = 0; /* current offset into buf */
! 1454: u16 _t; /* used by the macros */
! 1455:
! 1456: APPEND16(trans_id);
! 1457: APPEND16(0x0100); /* standard query, recusion needed */
! 1458: APPEND16(1); /* one question */
! 1459: APPEND16(0); /* no answers */
! 1460: APPEND16(0); /* no authority */
! 1461: APPEND16(0); /* no additional */
! 1462:
! 1463: j = dnsname_to_labels(buf, buf_len, j, name, name_len, NULL);
! 1464: if (j < 0) {
! 1465: return (int)j;
! 1466: }
! 1467:
! 1468: APPEND16(type);
! 1469: APPEND16(class);
! 1470:
! 1471: return (int)j;
! 1472: overflow:
! 1473: return (-1);
! 1474: }
! 1475:
! 1476: /* exported function */
! 1477: struct evdns_server_port *
! 1478: evdns_add_server_port(int socket, int is_tcp, evdns_request_callback_fn_type cb, void *user_data)
! 1479: {
! 1480: struct evdns_server_port *port;
! 1481: if (!(port = malloc(sizeof(struct evdns_server_port))))
! 1482: return NULL;
! 1483: memset(port, 0, sizeof(struct evdns_server_port));
! 1484:
! 1485: assert(!is_tcp); /* TCP sockets not yet implemented */
! 1486: port->socket = socket;
! 1487: port->refcnt = 1;
! 1488: port->choked = 0;
! 1489: port->closing = 0;
! 1490: port->user_callback = cb;
! 1491: port->user_data = user_data;
! 1492: port->pending_replies = NULL;
! 1493:
! 1494: event_set(&port->event, port->socket, EV_READ | EV_PERSIST,
! 1495: server_port_ready_callback, port);
! 1496: event_add(&port->event, NULL); /* check return. */
! 1497: return port;
! 1498: }
! 1499:
! 1500: /* exported function */
! 1501: void
! 1502: evdns_close_server_port(struct evdns_server_port *port)
! 1503: {
! 1504: if (--port->refcnt == 0)
! 1505: server_port_free(port);
! 1506: port->closing = 1;
! 1507: }
! 1508:
! 1509: /* exported function */
! 1510: int
! 1511: evdns_server_request_add_reply(struct evdns_server_request *_req, int section, const char *name, int type, int class, int ttl, int datalen, int is_name, const char *data)
! 1512: {
! 1513: struct server_request *req = TO_SERVER_REQUEST(_req);
! 1514: struct server_reply_item **itemp, *item;
! 1515: int *countp;
! 1516:
! 1517: if (req->response) /* have we already answered? */
! 1518: return (-1);
! 1519:
! 1520: switch (section) {
! 1521: case EVDNS_ANSWER_SECTION:
! 1522: itemp = &req->answer;
! 1523: countp = &req->n_answer;
! 1524: break;
! 1525: case EVDNS_AUTHORITY_SECTION:
! 1526: itemp = &req->authority;
! 1527: countp = &req->n_authority;
! 1528: break;
! 1529: case EVDNS_ADDITIONAL_SECTION:
! 1530: itemp = &req->additional;
! 1531: countp = &req->n_additional;
! 1532: break;
! 1533: default:
! 1534: return (-1);
! 1535: }
! 1536: while (*itemp) {
! 1537: itemp = &((*itemp)->next);
! 1538: }
! 1539: item = malloc(sizeof(struct server_reply_item));
! 1540: if (!item)
! 1541: return -1;
! 1542: item->next = NULL;
! 1543: if (!(item->name = strdup(name))) {
! 1544: free(item);
! 1545: return -1;
! 1546: }
! 1547: item->type = type;
! 1548: item->dns_question_class = class;
! 1549: item->ttl = ttl;
! 1550: item->is_name = is_name != 0;
! 1551: item->datalen = 0;
! 1552: item->data = NULL;
! 1553: if (data) {
! 1554: if (item->is_name) {
! 1555: if (!(item->data = strdup(data))) {
! 1556: free(item->name);
! 1557: free(item);
! 1558: return -1;
! 1559: }
! 1560: item->datalen = (u16)-1;
! 1561: } else {
! 1562: if (!(item->data = malloc(datalen))) {
! 1563: free(item->name);
! 1564: free(item);
! 1565: return -1;
! 1566: }
! 1567: item->datalen = datalen;
! 1568: memcpy(item->data, data, datalen);
! 1569: }
! 1570: }
! 1571:
! 1572: *itemp = item;
! 1573: ++(*countp);
! 1574: return 0;
! 1575: }
! 1576:
! 1577: /* exported function */
! 1578: int
! 1579: evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl)
! 1580: {
! 1581: return evdns_server_request_add_reply(
! 1582: req, EVDNS_ANSWER_SECTION, name, TYPE_A, CLASS_INET,
! 1583: ttl, n*4, 0, addrs);
! 1584: }
! 1585:
! 1586: /* exported function */
! 1587: int
! 1588: evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl)
! 1589: {
! 1590: return evdns_server_request_add_reply(
! 1591: req, EVDNS_ANSWER_SECTION, name, TYPE_AAAA, CLASS_INET,
! 1592: ttl, n*16, 0, addrs);
! 1593: }
! 1594:
! 1595: /* exported function */
! 1596: int
! 1597: evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl)
! 1598: {
! 1599: u32 a;
! 1600: char buf[32];
! 1601: assert(in || inaddr_name);
! 1602: assert(!(in && inaddr_name));
! 1603: if (in) {
! 1604: a = ntohl(in->s_addr);
! 1605: evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
! 1606: (int)(u8)((a )&0xff),
! 1607: (int)(u8)((a>>8 )&0xff),
! 1608: (int)(u8)((a>>16)&0xff),
! 1609: (int)(u8)((a>>24)&0xff));
! 1610: inaddr_name = buf;
! 1611: }
! 1612: return evdns_server_request_add_reply(
! 1613: req, EVDNS_ANSWER_SECTION, inaddr_name, TYPE_PTR, CLASS_INET,
! 1614: ttl, -1, 1, hostname);
! 1615: }
! 1616:
! 1617: /* exported function */
! 1618: int
! 1619: evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl)
! 1620: {
! 1621: return evdns_server_request_add_reply(
! 1622: req, EVDNS_ANSWER_SECTION, name, TYPE_CNAME, CLASS_INET,
! 1623: ttl, -1, 1, cname);
! 1624: }
! 1625:
! 1626:
! 1627: static int
! 1628: evdns_server_request_format_response(struct server_request *req, int err)
! 1629: {
! 1630: unsigned char buf[1500];
! 1631: size_t buf_len = sizeof(buf);
! 1632: off_t j = 0, r;
! 1633: u16 _t;
! 1634: u32 _t32;
! 1635: int i;
! 1636: u16 flags;
! 1637: struct dnslabel_table table;
! 1638:
! 1639: if (err < 0 || err > 15) return -1;
! 1640:
! 1641: /* Set response bit and error code; copy OPCODE and RD fields from
! 1642: * question; copy RA and AA if set by caller. */
! 1643: flags = req->base.flags;
! 1644: flags |= (0x8000 | err);
! 1645:
! 1646: dnslabel_table_init(&table);
! 1647: APPEND16(req->trans_id);
! 1648: APPEND16(flags);
! 1649: APPEND16(req->base.nquestions);
! 1650: APPEND16(req->n_answer);
! 1651: APPEND16(req->n_authority);
! 1652: APPEND16(req->n_additional);
! 1653:
! 1654: /* Add questions. */
! 1655: for (i=0; i < req->base.nquestions; ++i) {
! 1656: const char *s = req->base.questions[i]->name;
! 1657: j = dnsname_to_labels(buf, buf_len, j, s, strlen(s), &table);
! 1658: if (j < 0) {
! 1659: dnslabel_clear(&table);
! 1660: return (int) j;
! 1661: }
! 1662: APPEND16(req->base.questions[i]->type);
! 1663: APPEND16(req->base.questions[i]->dns_question_class);
! 1664: }
! 1665:
! 1666: /* Add answer, authority, and additional sections. */
! 1667: for (i=0; i<3; ++i) {
! 1668: struct server_reply_item *item;
! 1669: if (i==0)
! 1670: item = req->answer;
! 1671: else if (i==1)
! 1672: item = req->authority;
! 1673: else
! 1674: item = req->additional;
! 1675: while (item) {
! 1676: r = dnsname_to_labels(buf, buf_len, j, item->name, strlen(item->name), &table);
! 1677: if (r < 0)
! 1678: goto overflow;
! 1679: j = r;
! 1680:
! 1681: APPEND16(item->type);
! 1682: APPEND16(item->dns_question_class);
! 1683: APPEND32(item->ttl);
! 1684: if (item->is_name) {
! 1685: off_t len_idx = j, name_start;
! 1686: j += 2;
! 1687: name_start = j;
! 1688: r = dnsname_to_labels(buf, buf_len, j, item->data, strlen(item->data), &table);
! 1689: if (r < 0)
! 1690: goto overflow;
! 1691: j = r;
! 1692: _t = htons( (short) (j-name_start) );
! 1693: memcpy(buf+len_idx, &_t, 2);
! 1694: } else {
! 1695: APPEND16(item->datalen);
! 1696: if (j+item->datalen > (off_t)buf_len)
! 1697: goto overflow;
! 1698: memcpy(buf+j, item->data, item->datalen);
! 1699: j += item->datalen;
! 1700: }
! 1701: item = item->next;
! 1702: }
! 1703: }
! 1704:
! 1705: if (j > 512) {
! 1706: overflow:
! 1707: j = 512;
! 1708: buf[2] |= 0x02; /* set the truncated bit. */
! 1709: }
! 1710:
! 1711: req->response_len = j;
! 1712:
! 1713: if (!(req->response = malloc(req->response_len))) {
! 1714: server_request_free_answers(req);
! 1715: dnslabel_clear(&table);
! 1716: return (-1);
! 1717: }
! 1718: memcpy(req->response, buf, req->response_len);
! 1719: server_request_free_answers(req);
! 1720: dnslabel_clear(&table);
! 1721: return (0);
! 1722: }
! 1723:
! 1724: /* exported function */
! 1725: int
! 1726: evdns_server_request_respond(struct evdns_server_request *_req, int err)
! 1727: {
! 1728: struct server_request *req = TO_SERVER_REQUEST(_req);
! 1729: struct evdns_server_port *port = req->port;
! 1730: int r;
! 1731: if (!req->response) {
! 1732: if ((r = evdns_server_request_format_response(req, err))<0)
! 1733: return r;
! 1734: }
! 1735:
! 1736: r = sendto(port->socket, req->response, req->response_len, 0,
! 1737: (struct sockaddr*) &req->addr, req->addrlen);
! 1738: if (r<0) {
! 1739: int sock_err = last_error(port->socket);
! 1740: if (! error_is_eagain(sock_err))
! 1741: return -1;
! 1742:
! 1743: if (port->pending_replies) {
! 1744: req->prev_pending = port->pending_replies->prev_pending;
! 1745: req->next_pending = port->pending_replies;
! 1746: req->prev_pending->next_pending =
! 1747: req->next_pending->prev_pending = req;
! 1748: } else {
! 1749: req->prev_pending = req->next_pending = req;
! 1750: port->pending_replies = req;
! 1751: port->choked = 1;
! 1752:
! 1753: (void) event_del(&port->event);
! 1754: event_set(&port->event, port->socket, (port->closing?0:EV_READ) | EV_WRITE | EV_PERSIST, server_port_ready_callback, port);
! 1755:
! 1756: if (event_add(&port->event, NULL) < 0) {
! 1757: log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server");
! 1758: }
! 1759:
! 1760: }
! 1761:
! 1762: return 1;
! 1763: }
! 1764: if (server_request_free(req))
! 1765: return 0;
! 1766:
! 1767: if (port->pending_replies)
! 1768: server_port_flush(port);
! 1769:
! 1770: return 0;
! 1771: }
! 1772:
! 1773: /* Free all storage held by RRs in req. */
! 1774: static void
! 1775: server_request_free_answers(struct server_request *req)
! 1776: {
! 1777: struct server_reply_item *victim, *next, **list;
! 1778: int i;
! 1779: for (i = 0; i < 3; ++i) {
! 1780: if (i==0)
! 1781: list = &req->answer;
! 1782: else if (i==1)
! 1783: list = &req->authority;
! 1784: else
! 1785: list = &req->additional;
! 1786:
! 1787: victim = *list;
! 1788: while (victim) {
! 1789: next = victim->next;
! 1790: free(victim->name);
! 1791: if (victim->data)
! 1792: free(victim->data);
! 1793: free(victim);
! 1794: victim = next;
! 1795: }
! 1796: *list = NULL;
! 1797: }
! 1798: }
! 1799:
! 1800: /* Free all storage held by req, and remove links to it. */
! 1801: /* return true iff we just wound up freeing the server_port. */
! 1802: static int
! 1803: server_request_free(struct server_request *req)
! 1804: {
! 1805: int i, rc=1;
! 1806: if (req->base.questions) {
! 1807: for (i = 0; i < req->base.nquestions; ++i)
! 1808: free(req->base.questions[i]);
! 1809: free(req->base.questions);
! 1810: }
! 1811:
! 1812: if (req->port) {
! 1813: if (req->port->pending_replies == req) {
! 1814: if (req->next_pending)
! 1815: req->port->pending_replies = req->next_pending;
! 1816: else
! 1817: req->port->pending_replies = NULL;
! 1818: }
! 1819: rc = --req->port->refcnt;
! 1820: }
! 1821:
! 1822: if (req->response) {
! 1823: free(req->response);
! 1824: }
! 1825:
! 1826: server_request_free_answers(req);
! 1827:
! 1828: if (req->next_pending && req->next_pending != req) {
! 1829: req->next_pending->prev_pending = req->prev_pending;
! 1830: req->prev_pending->next_pending = req->next_pending;
! 1831: }
! 1832:
! 1833: if (rc == 0) {
! 1834: server_port_free(req->port);
! 1835: free(req);
! 1836: return (1);
! 1837: }
! 1838: free(req);
! 1839: return (0);
! 1840: }
! 1841:
! 1842: /* Free all storage held by an evdns_server_port. Only called when */
! 1843: static void
! 1844: server_port_free(struct evdns_server_port *port)
! 1845: {
! 1846: assert(port);
! 1847: assert(!port->refcnt);
! 1848: assert(!port->pending_replies);
! 1849: if (port->socket > 0) {
! 1850: CLOSE_SOCKET(port->socket);
! 1851: port->socket = -1;
! 1852: }
! 1853: (void) event_del(&port->event);
! 1854: /* XXXX actually free the port? -NM */
! 1855: }
! 1856:
! 1857: /* exported function */
! 1858: int
! 1859: evdns_server_request_drop(struct evdns_server_request *_req)
! 1860: {
! 1861: struct server_request *req = TO_SERVER_REQUEST(_req);
! 1862: server_request_free(req);
! 1863: return 0;
! 1864: }
! 1865:
! 1866: /* exported function */
! 1867: int
! 1868: evdns_server_request_get_requesting_addr(struct evdns_server_request *_req, struct sockaddr *sa, int addr_len)
! 1869: {
! 1870: struct server_request *req = TO_SERVER_REQUEST(_req);
! 1871: if (addr_len < (int)req->addrlen)
! 1872: return -1;
! 1873: memcpy(sa, &(req->addr), req->addrlen);
! 1874: return req->addrlen;
! 1875: }
! 1876:
! 1877: #undef APPEND16
! 1878: #undef APPEND32
! 1879:
! 1880: /* this is a libevent callback function which is called when a request */
! 1881: /* has timed out. */
! 1882: static void
! 1883: evdns_request_timeout_callback(int fd, short events, void *arg) {
! 1884: struct request *const req = (struct request *) arg;
! 1885: (void) fd;
! 1886: (void) events;
! 1887:
! 1888: log(EVDNS_LOG_DEBUG, "Request %lx timed out", (unsigned long) arg);
! 1889:
! 1890: req->ns->timedout++;
! 1891: if (req->ns->timedout > global_max_nameserver_timeout) {
! 1892: req->ns->timedout = 0;
! 1893: nameserver_failed(req->ns, "request timed out.");
! 1894: }
! 1895:
! 1896: (void) evtimer_del(&req->timeout_event);
! 1897: if (req->tx_count >= global_max_retransmits) {
! 1898: /* this request has failed */
! 1899: reply_callback(req, 0, DNS_ERR_TIMEOUT, NULL);
! 1900: request_finished(req, &req_head);
! 1901: } else {
! 1902: /* retransmit it */
! 1903: evdns_request_transmit(req);
! 1904: }
! 1905: }
! 1906:
! 1907: /* try to send a request to a given server. */
! 1908: /* */
! 1909: /* return: */
! 1910: /* 0 ok */
! 1911: /* 1 temporary failure */
! 1912: /* 2 other failure */
! 1913: static int
! 1914: evdns_request_transmit_to(struct request *req, struct nameserver *server) {
! 1915: struct sockaddr_in sin;
! 1916: int r;
! 1917: memset(&sin, 0, sizeof(sin));
! 1918: sin.sin_addr.s_addr = req->ns->address;
! 1919: sin.sin_port = req->ns->port;
! 1920: sin.sin_family = AF_INET;
! 1921:
! 1922: r = sendto(server->socket, req->request, req->request_len, 0,
! 1923: (struct sockaddr*)&sin, sizeof(sin));
! 1924: if (r < 0) {
! 1925: int err = last_error(server->socket);
! 1926: if (error_is_eagain(err)) return 1;
! 1927: nameserver_failed(req->ns, strerror(err));
! 1928: return 2;
! 1929: } else if (r != (int)req->request_len) {
! 1930: return 1; /* short write */
! 1931: } else {
! 1932: return 0;
! 1933: }
! 1934: }
! 1935:
! 1936: /* try to send a request, updating the fields of the request */
! 1937: /* as needed */
! 1938: /* */
! 1939: /* return: */
! 1940: /* 0 ok */
! 1941: /* 1 failed */
! 1942: static int
! 1943: evdns_request_transmit(struct request *req) {
! 1944: int retcode = 0, r;
! 1945:
! 1946: /* if we fail to send this packet then this flag marks it */
! 1947: /* for evdns_transmit */
! 1948: req->transmit_me = 1;
! 1949: if (req->trans_id == 0xffff) abort();
! 1950:
! 1951: if (req->ns->choked) {
! 1952: /* don't bother trying to write to a socket */
! 1953: /* which we have had EAGAIN from */
! 1954: return 1;
! 1955: }
! 1956:
! 1957: r = evdns_request_transmit_to(req, req->ns);
! 1958: switch (r) {
! 1959: case 1:
! 1960: /* temp failure */
! 1961: req->ns->choked = 1;
! 1962: nameserver_write_waiting(req->ns, 1);
! 1963: return 1;
! 1964: case 2:
! 1965: /* failed in some other way */
! 1966: retcode = 1;
! 1967: /* fall through */
! 1968: default:
! 1969: /* all ok */
! 1970: log(EVDNS_LOG_DEBUG,
! 1971: "Setting timeout for request %lx", (unsigned long) req);
! 1972: if (evtimer_add(&req->timeout_event, &global_timeout) < 0) {
! 1973: log(EVDNS_LOG_WARN,
! 1974: "Error from libevent when adding timer for request %lx",
! 1975: (unsigned long) req);
! 1976: /* ???? Do more? */
! 1977: }
! 1978: req->tx_count++;
! 1979: req->transmit_me = 0;
! 1980: return retcode;
! 1981: }
! 1982: }
! 1983:
! 1984: static void
! 1985: nameserver_probe_callback(int result, char type, int count, int ttl, void *addresses, void *arg) {
! 1986: struct nameserver *const ns = (struct nameserver *) arg;
! 1987: (void) type;
! 1988: (void) count;
! 1989: (void) ttl;
! 1990: (void) addresses;
! 1991:
! 1992: if (result == DNS_ERR_NONE || result == DNS_ERR_NOTEXIST) {
! 1993: /* this is a good reply */
! 1994: nameserver_up(ns);
! 1995: } else nameserver_probe_failed(ns);
! 1996: }
! 1997:
! 1998: static void
! 1999: nameserver_send_probe(struct nameserver *const ns) {
! 2000: struct request *req;
! 2001: /* here we need to send a probe to a given nameserver */
! 2002: /* in the hope that it is up now. */
! 2003:
! 2004: log(EVDNS_LOG_DEBUG, "Sending probe to %s", debug_ntoa(ns->address));
! 2005:
! 2006: req = request_new(TYPE_A, "www.google.com", DNS_QUERY_NO_SEARCH, nameserver_probe_callback, ns);
! 2007: if (!req) return;
! 2008: /* we force this into the inflight queue no matter what */
! 2009: request_trans_id_set(req, transaction_id_pick());
! 2010: req->ns = ns;
! 2011: request_submit(req);
! 2012: }
! 2013:
! 2014: /* returns: */
! 2015: /* 0 didn't try to transmit anything */
! 2016: /* 1 tried to transmit something */
! 2017: static int
! 2018: evdns_transmit(void) {
! 2019: char did_try_to_transmit = 0;
! 2020:
! 2021: if (req_head) {
! 2022: struct request *const started_at = req_head, *req = req_head;
! 2023: /* first transmit all the requests which are currently waiting */
! 2024: do {
! 2025: if (req->transmit_me) {
! 2026: did_try_to_transmit = 1;
! 2027: evdns_request_transmit(req);
! 2028: }
! 2029:
! 2030: req = req->next;
! 2031: } while (req != started_at);
! 2032: }
! 2033:
! 2034: return did_try_to_transmit;
! 2035: }
! 2036:
! 2037: /* exported function */
! 2038: int
! 2039: evdns_count_nameservers(void)
! 2040: {
! 2041: const struct nameserver *server = server_head;
! 2042: int n = 0;
! 2043: if (!server)
! 2044: return 0;
! 2045: do {
! 2046: ++n;
! 2047: server = server->next;
! 2048: } while (server != server_head);
! 2049: return n;
! 2050: }
! 2051:
! 2052: /* exported function */
! 2053: int
! 2054: evdns_clear_nameservers_and_suspend(void)
! 2055: {
! 2056: struct nameserver *server = server_head, *started_at = server_head;
! 2057: struct request *req = req_head, *req_started_at = req_head;
! 2058:
! 2059: if (!server)
! 2060: return 0;
! 2061: while (1) {
! 2062: struct nameserver *next = server->next;
! 2063: (void) event_del(&server->event);
! 2064: if (evtimer_initialized(&server->timeout_event))
! 2065: (void) evtimer_del(&server->timeout_event);
! 2066: if (server->socket >= 0)
! 2067: CLOSE_SOCKET(server->socket);
! 2068: free(server);
! 2069: if (next == started_at)
! 2070: break;
! 2071: server = next;
! 2072: }
! 2073: server_head = NULL;
! 2074: global_good_nameservers = 0;
! 2075:
! 2076: while (req) {
! 2077: struct request *next = req->next;
! 2078: req->tx_count = req->reissue_count = 0;
! 2079: req->ns = NULL;
! 2080: /* ???? What to do about searches? */
! 2081: (void) evtimer_del(&req->timeout_event);
! 2082: req->trans_id = 0;
! 2083: req->transmit_me = 0;
! 2084:
! 2085: global_requests_waiting++;
! 2086: evdns_request_insert(req, &req_waiting_head);
! 2087: /* We want to insert these suspended elements at the front of
! 2088: * the waiting queue, since they were pending before any of
! 2089: * the waiting entries were added. This is a circular list,
! 2090: * so we can just shift the start back by one.*/
! 2091: req_waiting_head = req_waiting_head->prev;
! 2092:
! 2093: if (next == req_started_at)
! 2094: break;
! 2095: req = next;
! 2096: }
! 2097: req_head = NULL;
! 2098: global_requests_inflight = 0;
! 2099:
! 2100: return 0;
! 2101: }
! 2102:
! 2103:
! 2104: /* exported function */
! 2105: int
! 2106: evdns_resume(void)
! 2107: {
! 2108: evdns_requests_pump_waiting_queue();
! 2109: return 0;
! 2110: }
! 2111:
! 2112: static int
! 2113: _evdns_nameserver_add_impl(unsigned long int address, int port) {
! 2114: /* first check to see if we already have this nameserver */
! 2115:
! 2116: const struct nameserver *server = server_head, *const started_at = server_head;
! 2117: struct nameserver *ns;
! 2118: int err = 0;
! 2119: if (server) {
! 2120: do {
! 2121: if (server->address == address) return 3;
! 2122: server = server->next;
! 2123: } while (server != started_at);
! 2124: }
! 2125:
! 2126: ns = (struct nameserver *) malloc(sizeof(struct nameserver));
! 2127: if (!ns) return -1;
! 2128:
! 2129: memset(ns, 0, sizeof(struct nameserver));
! 2130:
! 2131: evtimer_set(&ns->timeout_event, nameserver_prod_callback, ns);
! 2132:
! 2133: ns->socket = socket(PF_INET, SOCK_DGRAM, 0);
! 2134: if (ns->socket < 0) { err = 1; goto out1; }
! 2135: evutil_make_socket_nonblocking(ns->socket);
! 2136:
! 2137: ns->address = address;
! 2138: ns->port = htons(port);
! 2139: ns->state = 1;
! 2140: event_set(&ns->event, ns->socket, EV_READ | EV_PERSIST, nameserver_ready_callback, ns);
! 2141: if (event_add(&ns->event, NULL) < 0) {
! 2142: err = 2;
! 2143: goto out2;
! 2144: }
! 2145:
! 2146: log(EVDNS_LOG_DEBUG, "Added nameserver %s", debug_ntoa(address));
! 2147:
! 2148: /* insert this nameserver into the list of them */
! 2149: if (!server_head) {
! 2150: ns->next = ns->prev = ns;
! 2151: server_head = ns;
! 2152: } else {
! 2153: ns->next = server_head->next;
! 2154: ns->prev = server_head;
! 2155: server_head->next = ns;
! 2156: if (server_head->prev == server_head) {
! 2157: server_head->prev = ns;
! 2158: }
! 2159: }
! 2160:
! 2161: global_good_nameservers++;
! 2162:
! 2163: return 0;
! 2164:
! 2165: out2:
! 2166: CLOSE_SOCKET(ns->socket);
! 2167: out1:
! 2168: free(ns);
! 2169: log(EVDNS_LOG_WARN, "Unable to add nameserver %s: error %d", debug_ntoa(address), err);
! 2170: return err;
! 2171: }
! 2172:
! 2173: /* exported function */
! 2174: int
! 2175: evdns_nameserver_add(unsigned long int address) {
! 2176: return _evdns_nameserver_add_impl(address, 53);
! 2177: }
! 2178:
! 2179: /* exported function */
! 2180: int
! 2181: evdns_nameserver_ip_add(const char *ip_as_string) {
! 2182: struct in_addr ina;
! 2183: int port;
! 2184: char buf[20];
! 2185: const char *cp;
! 2186: cp = strchr(ip_as_string, ':');
! 2187: if (! cp) {
! 2188: cp = ip_as_string;
! 2189: port = 53;
! 2190: } else {
! 2191: port = strtoint(cp+1);
! 2192: if (port < 0 || port > 65535) {
! 2193: return 4;
! 2194: }
! 2195: if ((cp-ip_as_string) >= (int)sizeof(buf)) {
! 2196: return 4;
! 2197: }
! 2198: memcpy(buf, ip_as_string, cp-ip_as_string);
! 2199: buf[cp-ip_as_string] = '\0';
! 2200: cp = buf;
! 2201: }
! 2202: if (!inet_aton(cp, &ina)) {
! 2203: return 4;
! 2204: }
! 2205: return _evdns_nameserver_add_impl(ina.s_addr, port);
! 2206: }
! 2207:
! 2208: /* insert into the tail of the queue */
! 2209: static void
! 2210: evdns_request_insert(struct request *req, struct request **head) {
! 2211: if (!*head) {
! 2212: *head = req;
! 2213: req->next = req->prev = req;
! 2214: return;
! 2215: }
! 2216:
! 2217: req->prev = (*head)->prev;
! 2218: req->prev->next = req;
! 2219: req->next = *head;
! 2220: (*head)->prev = req;
! 2221: }
! 2222:
! 2223: static int
! 2224: string_num_dots(const char *s) {
! 2225: int count = 0;
! 2226: while ((s = strchr(s, '.'))) {
! 2227: s++;
! 2228: count++;
! 2229: }
! 2230: return count;
! 2231: }
! 2232:
! 2233: static struct request *
! 2234: request_new(int type, const char *name, int flags,
! 2235: evdns_callback_type callback, void *user_ptr) {
! 2236: const char issuing_now =
! 2237: (global_requests_inflight < global_max_requests_inflight) ? 1 : 0;
! 2238:
! 2239: const int name_len = strlen(name);
! 2240: const int request_max_len = evdns_request_len(name_len);
! 2241: const u16 trans_id = issuing_now ? transaction_id_pick() : 0xffff;
! 2242: /* the request data is alloced in a single block with the header */
! 2243: struct request *const req =
! 2244: (struct request *) malloc(sizeof(struct request) + request_max_len);
! 2245: int rlen;
! 2246: (void) flags;
! 2247:
! 2248: if (!req) return NULL;
! 2249: memset(req, 0, sizeof(struct request));
! 2250:
! 2251: evtimer_set(&req->timeout_event, evdns_request_timeout_callback, req);
! 2252:
! 2253: /* request data lives just after the header */
! 2254: req->request = ((u8 *) req) + sizeof(struct request);
! 2255: /* denotes that the request data shouldn't be free()ed */
! 2256: req->request_appended = 1;
! 2257: rlen = evdns_request_data_build(name, name_len, trans_id,
! 2258: type, CLASS_INET, req->request, request_max_len);
! 2259: if (rlen < 0)
! 2260: goto err1;
! 2261: req->request_len = rlen;
! 2262: req->trans_id = trans_id;
! 2263: req->tx_count = 0;
! 2264: req->request_type = type;
! 2265: req->user_pointer = user_ptr;
! 2266: req->user_callback = callback;
! 2267: req->ns = issuing_now ? nameserver_pick() : NULL;
! 2268: req->next = req->prev = NULL;
! 2269:
! 2270: return req;
! 2271: err1:
! 2272: free(req);
! 2273: return NULL;
! 2274: }
! 2275:
! 2276: static void
! 2277: request_submit(struct request *const req) {
! 2278: if (req->ns) {
! 2279: /* if it has a nameserver assigned then this is going */
! 2280: /* straight into the inflight queue */
! 2281: evdns_request_insert(req, &req_head);
! 2282: global_requests_inflight++;
! 2283: evdns_request_transmit(req);
! 2284: } else {
! 2285: evdns_request_insert(req, &req_waiting_head);
! 2286: global_requests_waiting++;
! 2287: }
! 2288: }
! 2289:
! 2290: /* exported function */
! 2291: int evdns_resolve_ipv4(const char *name, int flags,
! 2292: evdns_callback_type callback, void *ptr) {
! 2293: log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
! 2294: if (flags & DNS_QUERY_NO_SEARCH) {
! 2295: struct request *const req =
! 2296: request_new(TYPE_A, name, flags, callback, ptr);
! 2297: if (req == NULL)
! 2298: return (1);
! 2299: request_submit(req);
! 2300: return (0);
! 2301: } else {
! 2302: return (search_request_new(TYPE_A, name, flags, callback, ptr));
! 2303: }
! 2304: }
! 2305:
! 2306: /* exported function */
! 2307: int evdns_resolve_ipv6(const char *name, int flags,
! 2308: evdns_callback_type callback, void *ptr) {
! 2309: log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
! 2310: if (flags & DNS_QUERY_NO_SEARCH) {
! 2311: struct request *const req =
! 2312: request_new(TYPE_AAAA, name, flags, callback, ptr);
! 2313: if (req == NULL)
! 2314: return (1);
! 2315: request_submit(req);
! 2316: return (0);
! 2317: } else {
! 2318: return (search_request_new(TYPE_AAAA, name, flags, callback, ptr));
! 2319: }
! 2320: }
! 2321:
! 2322: int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) {
! 2323: char buf[32];
! 2324: struct request *req;
! 2325: u32 a;
! 2326: assert(in);
! 2327: a = ntohl(in->s_addr);
! 2328: evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
! 2329: (int)(u8)((a )&0xff),
! 2330: (int)(u8)((a>>8 )&0xff),
! 2331: (int)(u8)((a>>16)&0xff),
! 2332: (int)(u8)((a>>24)&0xff));
! 2333: log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
! 2334: req = request_new(TYPE_PTR, buf, flags, callback, ptr);
! 2335: if (!req) return 1;
! 2336: request_submit(req);
! 2337: return 0;
! 2338: }
! 2339:
! 2340: int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) {
! 2341: /* 32 nybbles, 32 periods, "ip6.arpa", NUL. */
! 2342: char buf[73];
! 2343: char *cp;
! 2344: struct request *req;
! 2345: int i;
! 2346: assert(in);
! 2347: cp = buf;
! 2348: for (i=15; i >= 0; --i) {
! 2349: u8 byte = in->s6_addr[i];
! 2350: *cp++ = "0123456789abcdef"[byte & 0x0f];
! 2351: *cp++ = '.';
! 2352: *cp++ = "0123456789abcdef"[byte >> 4];
! 2353: *cp++ = '.';
! 2354: }
! 2355: assert(cp + strlen("ip6.arpa") < buf+sizeof(buf));
! 2356: memcpy(cp, "ip6.arpa", strlen("ip6.arpa")+1);
! 2357: log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
! 2358: req = request_new(TYPE_PTR, buf, flags, callback, ptr);
! 2359: if (!req) return 1;
! 2360: request_submit(req);
! 2361: return 0;
! 2362: }
! 2363:
! 2364: /*/////////////////////////////////////////////////////////////////// */
! 2365: /* Search support */
! 2366: /* */
! 2367: /* the libc resolver has support for searching a number of domains */
! 2368: /* to find a name. If nothing else then it takes the single domain */
! 2369: /* from the gethostname() call. */
! 2370: /* */
! 2371: /* It can also be configured via the domain and search options in a */
! 2372: /* resolv.conf. */
! 2373: /* */
! 2374: /* The ndots option controls how many dots it takes for the resolver */
! 2375: /* to decide that a name is non-local and so try a raw lookup first. */
! 2376:
! 2377: struct search_domain {
! 2378: int len;
! 2379: struct search_domain *next;
! 2380: /* the text string is appended to this structure */
! 2381: };
! 2382:
! 2383: struct search_state {
! 2384: int refcount;
! 2385: int ndots;
! 2386: int num_domains;
! 2387: struct search_domain *head;
! 2388: };
! 2389:
! 2390: static struct search_state *global_search_state = NULL;
! 2391:
! 2392: static void
! 2393: search_state_decref(struct search_state *const state) {
! 2394: if (!state) return;
! 2395: state->refcount--;
! 2396: if (!state->refcount) {
! 2397: struct search_domain *next, *dom;
! 2398: for (dom = state->head; dom; dom = next) {
! 2399: next = dom->next;
! 2400: free(dom);
! 2401: }
! 2402: free(state);
! 2403: }
! 2404: }
! 2405:
! 2406: static struct search_state *
! 2407: search_state_new(void) {
! 2408: struct search_state *state = (struct search_state *) malloc(sizeof(struct search_state));
! 2409: if (!state) return NULL;
! 2410: memset(state, 0, sizeof(struct search_state));
! 2411: state->refcount = 1;
! 2412: state->ndots = 1;
! 2413:
! 2414: return state;
! 2415: }
! 2416:
! 2417: static void
! 2418: search_postfix_clear(void) {
! 2419: search_state_decref(global_search_state);
! 2420:
! 2421: global_search_state = search_state_new();
! 2422: }
! 2423:
! 2424: /* exported function */
! 2425: void
! 2426: evdns_search_clear(void) {
! 2427: search_postfix_clear();
! 2428: }
! 2429:
! 2430: static void
! 2431: search_postfix_add(const char *domain) {
! 2432: int domain_len;
! 2433: struct search_domain *sdomain;
! 2434: while (domain[0] == '.') domain++;
! 2435: domain_len = strlen(domain);
! 2436:
! 2437: if (!global_search_state) global_search_state = search_state_new();
! 2438: if (!global_search_state) return;
! 2439: global_search_state->num_domains++;
! 2440:
! 2441: sdomain = (struct search_domain *) malloc(sizeof(struct search_domain) + domain_len);
! 2442: if (!sdomain) return;
! 2443: memcpy( ((u8 *) sdomain) + sizeof(struct search_domain), domain, domain_len);
! 2444: sdomain->next = global_search_state->head;
! 2445: sdomain->len = domain_len;
! 2446:
! 2447: global_search_state->head = sdomain;
! 2448: }
! 2449:
! 2450: /* reverse the order of members in the postfix list. This is needed because, */
! 2451: /* when parsing resolv.conf we push elements in the wrong order */
! 2452: static void
! 2453: search_reverse(void) {
! 2454: struct search_domain *cur, *prev = NULL, *next;
! 2455: cur = global_search_state->head;
! 2456: while (cur) {
! 2457: next = cur->next;
! 2458: cur->next = prev;
! 2459: prev = cur;
! 2460: cur = next;
! 2461: }
! 2462:
! 2463: global_search_state->head = prev;
! 2464: }
! 2465:
! 2466: /* exported function */
! 2467: void
! 2468: evdns_search_add(const char *domain) {
! 2469: search_postfix_add(domain);
! 2470: }
! 2471:
! 2472: /* exported function */
! 2473: void
! 2474: evdns_search_ndots_set(const int ndots) {
! 2475: if (!global_search_state) global_search_state = search_state_new();
! 2476: if (!global_search_state) return;
! 2477: global_search_state->ndots = ndots;
! 2478: }
! 2479:
! 2480: static void
! 2481: search_set_from_hostname(void) {
! 2482: char hostname[HOST_NAME_MAX + 1], *domainname;
! 2483:
! 2484: search_postfix_clear();
! 2485: if (gethostname(hostname, sizeof(hostname))) return;
! 2486: domainname = strchr(hostname, '.');
! 2487: if (!domainname) return;
! 2488: search_postfix_add(domainname);
! 2489: }
! 2490:
! 2491: /* warning: returns malloced string */
! 2492: static char *
! 2493: search_make_new(const struct search_state *const state, int n, const char *const base_name) {
! 2494: const int base_len = strlen(base_name);
! 2495: const char need_to_append_dot = base_name[base_len - 1] == '.' ? 0 : 1;
! 2496: struct search_domain *dom;
! 2497:
! 2498: for (dom = state->head; dom; dom = dom->next) {
! 2499: if (!n--) {
! 2500: /* this is the postfix we want */
! 2501: /* the actual postfix string is kept at the end of the structure */
! 2502: const u8 *const postfix = ((u8 *) dom) + sizeof(struct search_domain);
! 2503: const int postfix_len = dom->len;
! 2504: char *const newname = (char *) malloc(base_len + need_to_append_dot + postfix_len + 1);
! 2505: if (!newname) return NULL;
! 2506: memcpy(newname, base_name, base_len);
! 2507: if (need_to_append_dot) newname[base_len] = '.';
! 2508: memcpy(newname + base_len + need_to_append_dot, postfix, postfix_len);
! 2509: newname[base_len + need_to_append_dot + postfix_len] = 0;
! 2510: return newname;
! 2511: }
! 2512: }
! 2513:
! 2514: /* we ran off the end of the list and still didn't find the requested string */
! 2515: abort();
! 2516: return NULL; /* unreachable; stops warnings in some compilers. */
! 2517: }
! 2518:
! 2519: static int
! 2520: search_request_new(int type, const char *const name, int flags, evdns_callback_type user_callback, void *user_arg) {
! 2521: assert(type == TYPE_A || type == TYPE_AAAA);
! 2522: if ( ((flags & DNS_QUERY_NO_SEARCH) == 0) &&
! 2523: global_search_state &&
! 2524: global_search_state->num_domains) {
! 2525: /* we have some domains to search */
! 2526: struct request *req;
! 2527: if (string_num_dots(name) >= global_search_state->ndots) {
! 2528: req = request_new(type, name, flags, user_callback, user_arg);
! 2529: if (!req) return 1;
! 2530: req->search_index = -1;
! 2531: } else {
! 2532: char *const new_name = search_make_new(global_search_state, 0, name);
! 2533: if (!new_name) return 1;
! 2534: req = request_new(type, new_name, flags, user_callback, user_arg);
! 2535: free(new_name);
! 2536: if (!req) return 1;
! 2537: req->search_index = 0;
! 2538: }
! 2539: req->search_origname = strdup(name);
! 2540: req->search_state = global_search_state;
! 2541: req->search_flags = flags;
! 2542: global_search_state->refcount++;
! 2543: request_submit(req);
! 2544: return 0;
! 2545: } else {
! 2546: struct request *const req = request_new(type, name, flags, user_callback, user_arg);
! 2547: if (!req) return 1;
! 2548: request_submit(req);
! 2549: return 0;
! 2550: }
! 2551: }
! 2552:
! 2553: /* this is called when a request has failed to find a name. We need to check */
! 2554: /* if it is part of a search and, if so, try the next name in the list */
! 2555: /* returns: */
! 2556: /* 0 another request has been submitted */
! 2557: /* 1 no more requests needed */
! 2558: static int
! 2559: search_try_next(struct request *const req) {
! 2560: if (req->search_state) {
! 2561: /* it is part of a search */
! 2562: char *new_name;
! 2563: struct request *newreq;
! 2564: req->search_index++;
! 2565: if (req->search_index >= req->search_state->num_domains) {
! 2566: /* no more postfixes to try, however we may need to try */
! 2567: /* this name without a postfix */
! 2568: if (string_num_dots(req->search_origname) < req->search_state->ndots) {
! 2569: /* yep, we need to try it raw */
! 2570: newreq = request_new(req->request_type, req->search_origname, req->search_flags, req->user_callback, req->user_pointer);
! 2571: log(EVDNS_LOG_DEBUG, "Search: trying raw query %s", req->search_origname);
! 2572: if (newreq) {
! 2573: request_submit(newreq);
! 2574: return 0;
! 2575: }
! 2576: }
! 2577: return 1;
! 2578: }
! 2579:
! 2580: new_name = search_make_new(req->search_state, req->search_index, req->search_origname);
! 2581: if (!new_name) return 1;
! 2582: log(EVDNS_LOG_DEBUG, "Search: now trying %s (%d)", new_name, req->search_index);
! 2583: newreq = request_new(req->request_type, new_name, req->search_flags, req->user_callback, req->user_pointer);
! 2584: free(new_name);
! 2585: if (!newreq) return 1;
! 2586: newreq->search_origname = req->search_origname;
! 2587: req->search_origname = NULL;
! 2588: newreq->search_state = req->search_state;
! 2589: newreq->search_flags = req->search_flags;
! 2590: newreq->search_index = req->search_index;
! 2591: newreq->search_state->refcount++;
! 2592: request_submit(newreq);
! 2593: return 0;
! 2594: }
! 2595: return 1;
! 2596: }
! 2597:
! 2598: static void
! 2599: search_request_finished(struct request *const req) {
! 2600: if (req->search_state) {
! 2601: search_state_decref(req->search_state);
! 2602: req->search_state = NULL;
! 2603: }
! 2604: if (req->search_origname) {
! 2605: free(req->search_origname);
! 2606: req->search_origname = NULL;
! 2607: }
! 2608: }
! 2609:
! 2610: /*/////////////////////////////////////////////////////////////////// */
! 2611: /* Parsing resolv.conf files */
! 2612:
! 2613: static void
! 2614: evdns_resolv_set_defaults(int flags) {
! 2615: /* if the file isn't found then we assume a local resolver */
! 2616: if (flags & DNS_OPTION_SEARCH) search_set_from_hostname();
! 2617: if (flags & DNS_OPTION_NAMESERVERS) evdns_nameserver_ip_add("127.0.0.1");
! 2618: }
! 2619:
! 2620: #ifndef HAVE_STRTOK_R
! 2621: static char *
! 2622: strtok_r(char *s, const char *delim, char **state) {
! 2623: return strtok(s, delim);
! 2624: }
! 2625: #endif
! 2626:
! 2627: /* helper version of atoi which returns -1 on error */
! 2628: static int
! 2629: strtoint(const char *const str) {
! 2630: char *endptr;
! 2631: const int r = strtol(str, &endptr, 10);
! 2632: if (*endptr) return -1;
! 2633: return r;
! 2634: }
! 2635:
! 2636: /* helper version of atoi that returns -1 on error and clips to bounds. */
! 2637: static int
! 2638: strtoint_clipped(const char *const str, int min, int max)
! 2639: {
! 2640: int r = strtoint(str);
! 2641: if (r == -1)
! 2642: return r;
! 2643: else if (r<min)
! 2644: return min;
! 2645: else if (r>max)
! 2646: return max;
! 2647: else
! 2648: return r;
! 2649: }
! 2650:
! 2651: /* exported function */
! 2652: int
! 2653: evdns_set_option(const char *option, const char *val, int flags)
! 2654: {
! 2655: if (!strncmp(option, "ndots:", 6)) {
! 2656: const int ndots = strtoint(val);
! 2657: if (ndots == -1) return -1;
! 2658: if (!(flags & DNS_OPTION_SEARCH)) return 0;
! 2659: log(EVDNS_LOG_DEBUG, "Setting ndots to %d", ndots);
! 2660: if (!global_search_state) global_search_state = search_state_new();
! 2661: if (!global_search_state) return -1;
! 2662: global_search_state->ndots = ndots;
! 2663: } else if (!strncmp(option, "timeout:", 8)) {
! 2664: const int timeout = strtoint(val);
! 2665: if (timeout == -1) return -1;
! 2666: if (!(flags & DNS_OPTION_MISC)) return 0;
! 2667: log(EVDNS_LOG_DEBUG, "Setting timeout to %d", timeout);
! 2668: global_timeout.tv_sec = timeout;
! 2669: } else if (!strncmp(option, "max-timeouts:", 12)) {
! 2670: const int maxtimeout = strtoint_clipped(val, 1, 255);
! 2671: if (maxtimeout == -1) return -1;
! 2672: if (!(flags & DNS_OPTION_MISC)) return 0;
! 2673: log(EVDNS_LOG_DEBUG, "Setting maximum allowed timeouts to %d",
! 2674: maxtimeout);
! 2675: global_max_nameserver_timeout = maxtimeout;
! 2676: } else if (!strncmp(option, "max-inflight:", 13)) {
! 2677: const int maxinflight = strtoint_clipped(val, 1, 65000);
! 2678: if (maxinflight == -1) return -1;
! 2679: if (!(flags & DNS_OPTION_MISC)) return 0;
! 2680: log(EVDNS_LOG_DEBUG, "Setting maximum inflight requests to %d",
! 2681: maxinflight);
! 2682: global_max_requests_inflight = maxinflight;
! 2683: } else if (!strncmp(option, "attempts:", 9)) {
! 2684: int retries = strtoint(val);
! 2685: if (retries == -1) return -1;
! 2686: if (retries > 255) retries = 255;
! 2687: if (!(flags & DNS_OPTION_MISC)) return 0;
! 2688: log(EVDNS_LOG_DEBUG, "Setting retries to %d", retries);
! 2689: global_max_retransmits = retries;
! 2690: }
! 2691: return 0;
! 2692: }
! 2693:
! 2694: static void
! 2695: resolv_conf_parse_line(char *const start, int flags) {
! 2696: char *strtok_state;
! 2697: static const char *const delims = " \t";
! 2698: #define NEXT_TOKEN strtok_r(NULL, delims, &strtok_state)
! 2699:
! 2700: char *const first_token = strtok_r(start, delims, &strtok_state);
! 2701: if (!first_token) return;
! 2702:
! 2703: if (!strcmp(first_token, "nameserver") && (flags & DNS_OPTION_NAMESERVERS)) {
! 2704: const char *const nameserver = NEXT_TOKEN;
! 2705: struct in_addr ina;
! 2706:
! 2707: if (nameserver && inet_aton(nameserver, &ina)) {
! 2708: /* address is valid */
! 2709: evdns_nameserver_add(ina.s_addr);
! 2710: }
! 2711: } else if (!strcmp(first_token, "domain") && (flags & DNS_OPTION_SEARCH)) {
! 2712: const char *const domain = NEXT_TOKEN;
! 2713: if (domain) {
! 2714: search_postfix_clear();
! 2715: search_postfix_add(domain);
! 2716: }
! 2717: } else if (!strcmp(first_token, "search") && (flags & DNS_OPTION_SEARCH)) {
! 2718: const char *domain;
! 2719: search_postfix_clear();
! 2720:
! 2721: while ((domain = NEXT_TOKEN)) {
! 2722: search_postfix_add(domain);
! 2723: }
! 2724: search_reverse();
! 2725: } else if (!strcmp(first_token, "options")) {
! 2726: const char *option;
! 2727: while ((option = NEXT_TOKEN)) {
! 2728: const char *val = strchr(option, ':');
! 2729: evdns_set_option(option, val ? val+1 : "", flags);
! 2730: }
! 2731: }
! 2732: #undef NEXT_TOKEN
! 2733: }
! 2734:
! 2735: /* exported function */
! 2736: /* returns: */
! 2737: /* 0 no errors */
! 2738: /* 1 failed to open file */
! 2739: /* 2 failed to stat file */
! 2740: /* 3 file too large */
! 2741: /* 4 out of memory */
! 2742: /* 5 short read from file */
! 2743: int
! 2744: evdns_resolv_conf_parse(int flags, const char *const filename) {
! 2745: struct stat st;
! 2746: int fd, n, r;
! 2747: u8 *resolv;
! 2748: char *start;
! 2749: int err = 0;
! 2750:
! 2751: log(EVDNS_LOG_DEBUG, "Parsing resolv.conf file %s", filename);
! 2752:
! 2753: fd = open(filename, O_RDONLY);
! 2754: if (fd < 0) {
! 2755: evdns_resolv_set_defaults(flags);
! 2756: return 1;
! 2757: }
! 2758:
! 2759: if (fstat(fd, &st)) { err = 2; goto out1; }
! 2760: if (!st.st_size) {
! 2761: evdns_resolv_set_defaults(flags);
! 2762: err = (flags & DNS_OPTION_NAMESERVERS) ? 6 : 0;
! 2763: goto out1;
! 2764: }
! 2765: if (st.st_size > 65535) { err = 3; goto out1; } /* no resolv.conf should be any bigger */
! 2766:
! 2767: resolv = (u8 *) malloc((size_t)st.st_size + 1);
! 2768: if (!resolv) { err = 4; goto out1; }
! 2769:
! 2770: n = 0;
! 2771: while ((r = read(fd, resolv+n, (size_t)st.st_size-n)) > 0) {
! 2772: n += r;
! 2773: if (n == st.st_size)
! 2774: break;
! 2775: assert(n < st.st_size);
! 2776: }
! 2777: if (r < 0) { err = 5; goto out2; }
! 2778: resolv[n] = 0; /* we malloced an extra byte; this should be fine. */
! 2779:
! 2780: start = (char *) resolv;
! 2781: for (;;) {
! 2782: char *const newline = strchr(start, '\n');
! 2783: if (!newline) {
! 2784: resolv_conf_parse_line(start, flags);
! 2785: break;
! 2786: } else {
! 2787: *newline = 0;
! 2788: resolv_conf_parse_line(start, flags);
! 2789: start = newline + 1;
! 2790: }
! 2791: }
! 2792:
! 2793: if (!server_head && (flags & DNS_OPTION_NAMESERVERS)) {
! 2794: /* no nameservers were configured. */
! 2795: evdns_nameserver_ip_add("127.0.0.1");
! 2796: err = 6;
! 2797: }
! 2798: if (flags & DNS_OPTION_SEARCH && (!global_search_state || global_search_state->num_domains == 0)) {
! 2799: search_set_from_hostname();
! 2800: }
! 2801:
! 2802: out2:
! 2803: free(resolv);
! 2804: out1:
! 2805: close(fd);
! 2806: return err;
! 2807: }
! 2808:
! 2809: #ifdef WIN32
! 2810: /* Add multiple nameservers from a space-or-comma-separated list. */
! 2811: static int
! 2812: evdns_nameserver_ip_add_line(const char *ips) {
! 2813: const char *addr;
! 2814: char *buf;
! 2815: int r;
! 2816: while (*ips) {
! 2817: while (ISSPACE(*ips) || *ips == ',' || *ips == '\t')
! 2818: ++ips;
! 2819: addr = ips;
! 2820: while (ISDIGIT(*ips) || *ips == '.' || *ips == ':')
! 2821: ++ips;
! 2822: buf = malloc(ips-addr+1);
! 2823: if (!buf) return 4;
! 2824: memcpy(buf, addr, ips-addr);
! 2825: buf[ips-addr] = '\0';
! 2826: r = evdns_nameserver_ip_add(buf);
! 2827: free(buf);
! 2828: if (r) return r;
! 2829: }
! 2830: return 0;
! 2831: }
! 2832:
! 2833: typedef DWORD(WINAPI *GetNetworkParams_fn_t)(FIXED_INFO *, DWORD*);
! 2834:
! 2835: /* Use the windows GetNetworkParams interface in iphlpapi.dll to */
! 2836: /* figure out what our nameservers are. */
! 2837: static int
! 2838: load_nameservers_with_getnetworkparams(void)
! 2839: {
! 2840: /* Based on MSDN examples and inspection of c-ares code. */
! 2841: FIXED_INFO *fixed;
! 2842: HMODULE handle = 0;
! 2843: ULONG size = sizeof(FIXED_INFO);
! 2844: void *buf = NULL;
! 2845: int status = 0, r, added_any;
! 2846: IP_ADDR_STRING *ns;
! 2847: GetNetworkParams_fn_t fn;
! 2848:
! 2849: if (!(handle = LoadLibraryA("iphlpapi.dll"))) {
! 2850: log(EVDNS_LOG_WARN, "Could not open iphlpapi.dll");
! 2851: status = -1;
! 2852: goto done;
! 2853: }
! 2854: if (!(fn = (GetNetworkParams_fn_t) GetProcAddress(handle, "GetNetworkParams"))) {
! 2855: log(EVDNS_LOG_WARN, "Could not get address of function.");
! 2856: status = -1;
! 2857: goto done;
! 2858: }
! 2859:
! 2860: buf = malloc(size);
! 2861: if (!buf) { status = 4; goto done; }
! 2862: fixed = buf;
! 2863: r = fn(fixed, &size);
! 2864: if (r != ERROR_SUCCESS && r != ERROR_BUFFER_OVERFLOW) {
! 2865: status = -1;
! 2866: goto done;
! 2867: }
! 2868: if (r != ERROR_SUCCESS) {
! 2869: free(buf);
! 2870: buf = malloc(size);
! 2871: if (!buf) { status = 4; goto done; }
! 2872: fixed = buf;
! 2873: r = fn(fixed, &size);
! 2874: if (r != ERROR_SUCCESS) {
! 2875: log(EVDNS_LOG_DEBUG, "fn() failed.");
! 2876: status = -1;
! 2877: goto done;
! 2878: }
! 2879: }
! 2880:
! 2881: assert(fixed);
! 2882: added_any = 0;
! 2883: ns = &(fixed->DnsServerList);
! 2884: while (ns) {
! 2885: r = evdns_nameserver_ip_add_line(ns->IpAddress.String);
! 2886: if (r) {
! 2887: log(EVDNS_LOG_DEBUG,"Could not add nameserver %s to list,error: %d",
! 2888: (ns->IpAddress.String),(int)GetLastError());
! 2889: status = r;
! 2890: goto done;
! 2891: } else {
! 2892: log(EVDNS_LOG_DEBUG,"Succesfully added %s as nameserver",ns->IpAddress.String);
! 2893: }
! 2894:
! 2895: added_any++;
! 2896: ns = ns->Next;
! 2897: }
! 2898:
! 2899: if (!added_any) {
! 2900: log(EVDNS_LOG_DEBUG, "No nameservers added.");
! 2901: status = -1;
! 2902: }
! 2903:
! 2904: done:
! 2905: if (buf)
! 2906: free(buf);
! 2907: if (handle)
! 2908: FreeLibrary(handle);
! 2909: return status;
! 2910: }
! 2911:
! 2912: static int
! 2913: config_nameserver_from_reg_key(HKEY key, const char *subkey)
! 2914: {
! 2915: char *buf;
! 2916: DWORD bufsz = 0, type = 0;
! 2917: int status = 0;
! 2918:
! 2919: if (RegQueryValueExA(key, subkey, 0, &type, NULL, &bufsz)
! 2920: != ERROR_MORE_DATA)
! 2921: return -1;
! 2922: if (!(buf = malloc(bufsz)))
! 2923: return -1;
! 2924:
! 2925: if (RegQueryValueExA(key, subkey, 0, &type, (LPBYTE)buf, &bufsz)
! 2926: == ERROR_SUCCESS && bufsz > 1) {
! 2927: status = evdns_nameserver_ip_add_line(buf);
! 2928: }
! 2929:
! 2930: free(buf);
! 2931: return status;
! 2932: }
! 2933:
! 2934: #define SERVICES_KEY "System\\CurrentControlSet\\Services\\"
! 2935: #define WIN_NS_9X_KEY SERVICES_KEY "VxD\\MSTCP"
! 2936: #define WIN_NS_NT_KEY SERVICES_KEY "Tcpip\\Parameters"
! 2937:
! 2938: static int
! 2939: load_nameservers_from_registry(void)
! 2940: {
! 2941: int found = 0;
! 2942: int r;
! 2943: #define TRY(k, name) \
! 2944: if (!found && config_nameserver_from_reg_key(k,name) == 0) { \
! 2945: log(EVDNS_LOG_DEBUG,"Found nameservers in %s/%s",#k,name); \
! 2946: found = 1; \
! 2947: } else if (!found) { \
! 2948: log(EVDNS_LOG_DEBUG,"Didn't find nameservers in %s/%s", \
! 2949: #k,#name); \
! 2950: }
! 2951:
! 2952: if (((int)GetVersion()) > 0) { /* NT */
! 2953: HKEY nt_key = 0, interfaces_key = 0;
! 2954:
! 2955: if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0,
! 2956: KEY_READ, &nt_key) != ERROR_SUCCESS) {
! 2957: log(EVDNS_LOG_DEBUG,"Couldn't open nt key, %d",(int)GetLastError());
! 2958: return -1;
! 2959: }
! 2960: r = RegOpenKeyExA(nt_key, "Interfaces", 0,
! 2961: KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS,
! 2962: &interfaces_key);
! 2963: if (r != ERROR_SUCCESS) {
! 2964: log(EVDNS_LOG_DEBUG,"Couldn't open interfaces key, %d",(int)GetLastError());
! 2965: return -1;
! 2966: }
! 2967: TRY(nt_key, "NameServer");
! 2968: TRY(nt_key, "DhcpNameServer");
! 2969: TRY(interfaces_key, "NameServer");
! 2970: TRY(interfaces_key, "DhcpNameServer");
! 2971: RegCloseKey(interfaces_key);
! 2972: RegCloseKey(nt_key);
! 2973: } else {
! 2974: HKEY win_key = 0;
! 2975: if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_NS_9X_KEY, 0,
! 2976: KEY_READ, &win_key) != ERROR_SUCCESS) {
! 2977: log(EVDNS_LOG_DEBUG, "Couldn't open registry key, %d", (int)GetLastError());
! 2978: return -1;
! 2979: }
! 2980: TRY(win_key, "NameServer");
! 2981: RegCloseKey(win_key);
! 2982: }
! 2983:
! 2984: if (found == 0) {
! 2985: log(EVDNS_LOG_WARN,"Didn't find any nameservers.");
! 2986: }
! 2987:
! 2988: return found ? 0 : -1;
! 2989: #undef TRY
! 2990: }
! 2991:
! 2992: int
! 2993: evdns_config_windows_nameservers(void)
! 2994: {
! 2995: if (load_nameservers_with_getnetworkparams() == 0)
! 2996: return 0;
! 2997: return load_nameservers_from_registry();
! 2998: }
! 2999: #endif
! 3000:
! 3001: int
! 3002: evdns_init(void)
! 3003: {
! 3004: int res = 0;
! 3005: #ifdef WIN32
! 3006: res = evdns_config_windows_nameservers();
! 3007: #else
! 3008: res = evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf");
! 3009: #endif
! 3010:
! 3011: return (res);
! 3012: }
! 3013:
! 3014: const char *
! 3015: evdns_err_to_string(int err)
! 3016: {
! 3017: switch (err) {
! 3018: case DNS_ERR_NONE: return "no error";
! 3019: case DNS_ERR_FORMAT: return "misformatted query";
! 3020: case DNS_ERR_SERVERFAILED: return "server failed";
! 3021: case DNS_ERR_NOTEXIST: return "name does not exist";
! 3022: case DNS_ERR_NOTIMPL: return "query not implemented";
! 3023: case DNS_ERR_REFUSED: return "refused";
! 3024:
! 3025: case DNS_ERR_TRUNCATED: return "reply truncated or ill-formed";
! 3026: case DNS_ERR_UNKNOWN: return "unknown";
! 3027: case DNS_ERR_TIMEOUT: return "request timed out";
! 3028: case DNS_ERR_SHUTDOWN: return "dns subsystem shut down";
! 3029: default: return "[Unknown error code]";
! 3030: }
! 3031: }
! 3032:
! 3033: void
! 3034: evdns_shutdown(int fail_requests)
! 3035: {
! 3036: struct nameserver *server, *server_next;
! 3037: struct search_domain *dom, *dom_next;
! 3038:
! 3039: while (req_head) {
! 3040: if (fail_requests)
! 3041: reply_callback(req_head, 0, DNS_ERR_SHUTDOWN, NULL);
! 3042: request_finished(req_head, &req_head);
! 3043: }
! 3044: while (req_waiting_head) {
! 3045: if (fail_requests)
! 3046: reply_callback(req_waiting_head, 0, DNS_ERR_SHUTDOWN, NULL);
! 3047: request_finished(req_waiting_head, &req_waiting_head);
! 3048: }
! 3049: global_requests_inflight = global_requests_waiting = 0;
! 3050:
! 3051: for (server = server_head; server; server = server_next) {
! 3052: server_next = server->next;
! 3053: if (server->socket >= 0)
! 3054: CLOSE_SOCKET(server->socket);
! 3055: (void) event_del(&server->event);
! 3056: if (server->state == 0)
! 3057: (void) event_del(&server->timeout_event);
! 3058: free(server);
! 3059: if (server_next == server_head)
! 3060: break;
! 3061: }
! 3062: server_head = NULL;
! 3063: global_good_nameservers = 0;
! 3064:
! 3065: if (global_search_state) {
! 3066: for (dom = global_search_state->head; dom; dom = dom_next) {
! 3067: dom_next = dom->next;
! 3068: free(dom);
! 3069: }
! 3070: free(global_search_state);
! 3071: global_search_state = NULL;
! 3072: }
! 3073: evdns_log_fn = NULL;
! 3074: }
! 3075:
! 3076: #ifdef EVDNS_MAIN
! 3077: void
! 3078: main_callback(int result, char type, int count, int ttl,
! 3079: void *addrs, void *orig) {
! 3080: char *n = (char*)orig;
! 3081: int i;
! 3082: for (i = 0; i < count; ++i) {
! 3083: if (type == DNS_IPv4_A) {
! 3084: printf("%s: %s\n", n, debug_ntoa(((u32*)addrs)[i]));
! 3085: } else if (type == DNS_PTR) {
! 3086: printf("%s: %s\n", n, ((char**)addrs)[i]);
! 3087: }
! 3088: }
! 3089: if (!count) {
! 3090: printf("%s: No answer (%d)\n", n, result);
! 3091: }
! 3092: fflush(stdout);
! 3093: }
! 3094: void
! 3095: evdns_server_callback(struct evdns_server_request *req, void *data)
! 3096: {
! 3097: int i, r;
! 3098: (void)data;
! 3099: /* dummy; give 192.168.11.11 as an answer for all A questions,
! 3100: * give foo.bar.example.com as an answer for all PTR questions. */
! 3101: for (i = 0; i < req->nquestions; ++i) {
! 3102: u32 ans = htonl(0xc0a80b0bUL);
! 3103: if (req->questions[i]->type == EVDNS_TYPE_A &&
! 3104: req->questions[i]->dns_question_class == EVDNS_CLASS_INET) {
! 3105: printf(" -- replying for %s (A)\n", req->questions[i]->name);
! 3106: r = evdns_server_request_add_a_reply(req, req->questions[i]->name,
! 3107: 1, &ans, 10);
! 3108: if (r<0)
! 3109: printf("eeep, didn't work.\n");
! 3110: } else if (req->questions[i]->type == EVDNS_TYPE_PTR &&
! 3111: req->questions[i]->dns_question_class == EVDNS_CLASS_INET) {
! 3112: printf(" -- replying for %s (PTR)\n", req->questions[i]->name);
! 3113: r = evdns_server_request_add_ptr_reply(req, NULL, req->questions[i]->name,
! 3114: "foo.bar.example.com", 10);
! 3115: } else {
! 3116: printf(" -- skipping %s [%d %d]\n", req->questions[i]->name,
! 3117: req->questions[i]->type, req->questions[i]->dns_question_class);
! 3118: }
! 3119: }
! 3120:
! 3121: r = evdns_request_respond(req, 0);
! 3122: if (r<0)
! 3123: printf("eeek, couldn't send reply.\n");
! 3124: }
! 3125:
! 3126: void
! 3127: logfn(int is_warn, const char *msg) {
! 3128: (void) is_warn;
! 3129: fprintf(stderr, "%s\n", msg);
! 3130: }
! 3131: int
! 3132: main(int c, char **v) {
! 3133: int idx;
! 3134: int reverse = 0, verbose = 1, servertest = 0;
! 3135: if (c<2) {
! 3136: fprintf(stderr, "syntax: %s [-x] [-v] hostname\n", v[0]);
! 3137: fprintf(stderr, "syntax: %s [-servertest]\n", v[0]);
! 3138: return 1;
! 3139: }
! 3140: idx = 1;
! 3141: while (idx < c && v[idx][0] == '-') {
! 3142: if (!strcmp(v[idx], "-x"))
! 3143: reverse = 1;
! 3144: else if (!strcmp(v[idx], "-v"))
! 3145: verbose = 1;
! 3146: else if (!strcmp(v[idx], "-servertest"))
! 3147: servertest = 1;
! 3148: else
! 3149: fprintf(stderr, "Unknown option %s\n", v[idx]);
! 3150: ++idx;
! 3151: }
! 3152: event_init();
! 3153: if (verbose)
! 3154: evdns_set_log_fn(logfn);
! 3155: evdns_resolv_conf_parse(DNS_OPTION_NAMESERVERS, "/etc/resolv.conf");
! 3156: if (servertest) {
! 3157: int sock;
! 3158: struct sockaddr_in my_addr;
! 3159: sock = socket(PF_INET, SOCK_DGRAM, 0);
! 3160: evutil_make_socket_nonblocking(sock);
! 3161: my_addr.sin_family = AF_INET;
! 3162: my_addr.sin_port = htons(10053);
! 3163: my_addr.sin_addr.s_addr = INADDR_ANY;
! 3164: if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr))<0) {
! 3165: perror("bind");
! 3166: exit(1);
! 3167: }
! 3168: evdns_add_server_port(sock, 0, evdns_server_callback, NULL);
! 3169: }
! 3170: for (; idx < c; ++idx) {
! 3171: if (reverse) {
! 3172: struct in_addr addr;
! 3173: if (!inet_aton(v[idx], &addr)) {
! 3174: fprintf(stderr, "Skipping non-IP %s\n", v[idx]);
! 3175: continue;
! 3176: }
! 3177: fprintf(stderr, "resolving %s...\n",v[idx]);
! 3178: evdns_resolve_reverse(&addr, 0, main_callback, v[idx]);
! 3179: } else {
! 3180: fprintf(stderr, "resolving (fwd) %s...\n",v[idx]);
! 3181: evdns_resolve_ipv4(v[idx], 0, main_callback, v[idx]);
! 3182: }
! 3183: }
! 3184: fflush(stdout);
! 3185: event_dispatch();
! 3186: return 0;
! 3187: }
! 3188: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>