mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-10 13:13:44 +01:00
r11584@Kushana: nickm | 2006-12-15 01:10:45 -0500
Try to reconcile (except for whitespace) eventdns with version in libevent, so it is easier for me to send merges. These changes should be cosmetic. (Ha!) svn:r9117
This commit is contained in:
parent
309c579452
commit
b16aa6412e
6
doc/TODO
6
doc/TODO
@ -134,6 +134,12 @@ d - Special-case localhost?
|
||||
- address_is_invalid_destination() is the right thing to call here
|
||||
(and feel free to make that function smarter)
|
||||
|
||||
d - Eventdns improvements
|
||||
- Have a way to query for AAAA and A records simultaneously.
|
||||
- Improve request API: At the very least, add the ability to construct
|
||||
a more-or-less arbitrary request and get a response.
|
||||
- (Can we suppress cnames? Should we?)
|
||||
|
||||
- Performance improvements
|
||||
|
||||
x - Better estimates in the directory of whether servers have good uptime
|
||||
|
@ -7,16 +7,13 @@
|
||||
* reformat the whitespace, add Tor dependencies, or so on.
|
||||
*
|
||||
* TODO:
|
||||
* - Have a way to query for AAAA and A records simultaneously.
|
||||
* - Improve request API: At the very least, add the ability to construct
|
||||
* a more-or-less arbitrary request and get a response.
|
||||
* - (Can we suppress cnames? Should we?)
|
||||
* - Replace all externally visible magic numbers with #defined constants.
|
||||
* - Write documentation for APIs of all external functions.
|
||||
*/
|
||||
|
||||
/* Async DNS Library
|
||||
* Adam Langley <agl@imperialviolet.org>
|
||||
* http://www.imperialviolet.org/eventdns.html
|
||||
* Public Domain code
|
||||
*
|
||||
* This software is Public Domain. To view a copy of the public domain dedication,
|
||||
@ -34,195 +31,9 @@
|
||||
* the source verbatim in their source distributions)
|
||||
*
|
||||
* Version: 0.1b
|
||||
*
|
||||
*
|
||||
* Welcome, gentle reader
|
||||
*
|
||||
* Async DNS lookups are really a whole lot harder than they should be,
|
||||
* mostly stemming from the fact that the libc resolver has never been
|
||||
* very good at them. Before you use this library you should see if libc
|
||||
* can do the job for you with the modern async call getaddrinfo_a
|
||||
* (see http://www.imperialviolet.org/page25.html#e498). Otherwise,
|
||||
* please continue.
|
||||
*
|
||||
* This code is based on libevent and you must call event_init before
|
||||
* any of the APIs in this file. You must also seed the OpenSSL random
|
||||
* source if you are using OpenSSL for ids (see below).
|
||||
*
|
||||
* This library is designed to be included and shipped with your source
|
||||
* code. You statically link with it. You should also test for the
|
||||
* existence of strtok_r and define HAVE_STRTOK_R if you have it.
|
||||
*
|
||||
* The DNS protocol requires a good source of id numbers and these
|
||||
* numbers should be unpredictable for spoofing reasons. There are
|
||||
* three methods for generating them here and you must define exactly
|
||||
* one of them. In increasing order of preference:
|
||||
*
|
||||
* DNS_USE_GETTIMEOFDAY_FOR_ID:
|
||||
* Using the bottom 16 bits of the usec result from gettimeofday. This
|
||||
* is a pretty poor solution but should work anywhere.
|
||||
* DNS_USE_CPU_CLOCK_FOR_ID:
|
||||
* Using the bottom 16 bits of the nsec result from the CPU's time
|
||||
* counter. This is better, but may not work everywhere. Requires
|
||||
* POSIX realtime support and you'll need to link against -lrt on
|
||||
* glibc systems at least.
|
||||
* DNS_USE_OPENSSL_FOR_ID:
|
||||
* Uses the OpenSSL RAND_bytes call to generate the data. You must
|
||||
* have seeded the pool before making any calls to this library.
|
||||
*
|
||||
* The library keeps track of the state of nameservers and will avoid
|
||||
* them when they go down. Otherwise it will round robin between them.
|
||||
*
|
||||
* Quick start guide:
|
||||
* #include "eventdns.h"
|
||||
* void callback(int result, char type, int count, int ttl,
|
||||
* void *addresses, void *arg);
|
||||
* evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf");
|
||||
* evdns_resolve("www.hostname.com", 0, callback, NULL);
|
||||
*
|
||||
* When the lookup is complete the callback function is called. The
|
||||
* first argument will be one of the DNS_ERR_* defines in eventdns.h.
|
||||
* Hopefully it will be DNS_ERR_NONE, in which case type will be
|
||||
* DNS_IPv4_A, count will be the number of IP addresses, ttl is the time
|
||||
* which the data can be cached for (in seconds), addresses will point
|
||||
* to an array of uint32_t's and arg will be whatever you passed to
|
||||
* evdns_resolve.
|
||||
*
|
||||
* Searching:
|
||||
*
|
||||
* In order for this library to be a good replacement for glibc's resolver it
|
||||
* supports searching. This involves setting a list of default domains, in
|
||||
* which names will be queried for. The number of dots in the query name
|
||||
* determines the order in which this list is used.
|
||||
*
|
||||
* Searching appears to be a single lookup from the point of view of the API,
|
||||
* although many DNS queries may be generated from a single call to
|
||||
* evdns_resolve. Searching can also drastically slow down the resolution
|
||||
* of names.
|
||||
*
|
||||
* To disable searching:
|
||||
* 1. Never set it up. If you never call evdns_resolv_conf_parse or
|
||||
* evdns_search_add then no searching will occur.
|
||||
*
|
||||
* 2. If you do call evdns_resolv_conf_parse then don't pass
|
||||
* DNS_OPTION_SEARCH (or DNS_OPTIONS_ALL, which implies it).
|
||||
*
|
||||
* 3. When calling evdns_resolve, pass the DNS_QUERY_NO_SEARCH flag.
|
||||
*
|
||||
* The order of searches depends on the number of dots in the name. If the
|
||||
* number is greater than the ndots setting then the names is first tried
|
||||
* globally. Otherwise each search domain is appended in turn.
|
||||
*
|
||||
* The ndots setting can either be set from a resolv.conf, or by calling
|
||||
* evdns_search_ndots_set.
|
||||
*
|
||||
* For example, with ndots set to 1 (the default) and a search domain list of
|
||||
* ["myhome.net"]:
|
||||
* Query: www
|
||||
* Order: www.myhome.net, www.
|
||||
*
|
||||
* Query: www.abc
|
||||
* Order: www.abc., www.abc.myhome.net
|
||||
*
|
||||
* API reference:
|
||||
*
|
||||
* int evdns_nameserver_add(unsigned long int address)
|
||||
* Add a nameserver. The address should be an IP address in
|
||||
* network byte order. The type of address is chosen so that
|
||||
* it matches in_addr.s_addr.
|
||||
* Returns non-zero on error.
|
||||
*
|
||||
* int evdns_nameserver_ip_add(const char *ip_as_string)
|
||||
* This wraps the above function by parsing a string as an IP
|
||||
* address and adds it as a nameserver.
|
||||
* Returns non-zero on error
|
||||
*
|
||||
* int evdns_resolve(const char *name, int flags,
|
||||
* evdns_callback_type callback,
|
||||
* void *ptr)
|
||||
* Resolve a name. The name parameter should be a DNS name.
|
||||
* The flags parameter should be 0, or DNS_QUERY_NO_SEARCH
|
||||
* which disables searching for this query. (see defn of
|
||||
* searching above).
|
||||
*
|
||||
* The callback argument is a function which is called when
|
||||
* this query completes and ptr is an argument which is passed
|
||||
* to that callback function.
|
||||
*
|
||||
* Returns non-zero on error
|
||||
*
|
||||
* void evdns_search_clear()
|
||||
* Clears the list of search domains
|
||||
*
|
||||
* void evdns_search_add(const char *domain)
|
||||
* Add a domain to the list of search domains
|
||||
*
|
||||
* void evdns_search_ndots_set(int ndots)
|
||||
* Set the number of dots which, when found in a name, causes
|
||||
* the first query to be without any search domain.
|
||||
*
|
||||
* int evdns_count_nameservers(void)
|
||||
* Return the number of configured nameservers (not necessarily the
|
||||
* number of running nameservers). This is useful for double-checking
|
||||
* whether our calls to the various nameserver configuration functions
|
||||
* have been successful.
|
||||
*
|
||||
* int evdns_clear_nameservers_and_suspend(void)
|
||||
* Remove all currently configured nameservers, and suspend all pending
|
||||
* resolves. Resolves will not necessarily be re-attempted until
|
||||
* evdns_resume() is called.
|
||||
*
|
||||
* int evdns_resume(void)
|
||||
* Re-attempt resolves left in limbo after an earlier call to
|
||||
* evdns_clear_nameservers_and_suspend().
|
||||
*
|
||||
* int evdns_config_windows_nameservers(void)
|
||||
* Attempt to configure a set of nameservers based on platform settings on
|
||||
* a win32 host. Preferentially tries to use GetNetworkParams; if that fails,
|
||||
* looks in the registry. Returns 0 on success, nonzero on failure.
|
||||
*
|
||||
* int evdns_resolv_conf_parse(int flags, const char *filename)
|
||||
* Parse a resolv.conf like file from the given filename.
|
||||
*
|
||||
* See the man page for resolv.conf for the format of this file.
|
||||
* The flags argument determines what information is parsed from
|
||||
* this file:
|
||||
* DNS_OPTION_SEARCH - domain, search and ndots options
|
||||
* DNS_OPTION_NAMESERVERS - nameserver lines
|
||||
* DNS_OPTION_MISC - timeout and attempts options
|
||||
* DNS_OPTIONS_ALL - all of the above
|
||||
* The following directives are not parsed from the file:
|
||||
* sortlist, rotate, no-check-names, inet6, debug
|
||||
*
|
||||
* Returns non-zero on error:
|
||||
* 0 no errors
|
||||
* 1 failed to open file
|
||||
* 2 failed to stat file
|
||||
* 3 file too large
|
||||
* 4 out of memory
|
||||
* 5 short read from file
|
||||
*
|
||||
* Internals:
|
||||
*
|
||||
* Requests are kept in two queues. The first is the inflight queue. In
|
||||
* this queue requests have an allocated transaction id and nameserver.
|
||||
* They will soon be transmitted if they haven't already been.
|
||||
*
|
||||
* The second is the waiting queue. The size of the inflight ring is
|
||||
* limited and all other requests wait in waiting queue for space. This
|
||||
* bounds the number of concurrent requests so that we don't flood the
|
||||
* nameserver. Several algorithms require a full walk of the inflight
|
||||
* queue and so bounding its size keeps thing going nicely under huge
|
||||
* (many thousands of requests) loads.
|
||||
*
|
||||
* If a nameserver loses too many requests it is considered down and we
|
||||
* try not to use it. After a while we send a probe to that nameserver
|
||||
* (a lookup for google.com) and, if it replies, we consider it working
|
||||
* again. If the nameserver fails a probe we wait longer to try again
|
||||
* with the next probe.
|
||||
*/
|
||||
|
||||
#include "eventdns.h"
|
||||
#include <sys/types.h>
|
||||
#include "eventdns_tor.h"
|
||||
//#define NDEBUG
|
||||
#include "../common/torint.h"
|
||||
@ -259,10 +70,11 @@
|
||||
#define _FORTIFY_SOURCE 3
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/time.h>
|
||||
// #include <stdint.h>
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
@ -274,6 +86,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "eventdns.h"
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
@ -312,8 +125,6 @@ typedef unsigned int uint;
|
||||
#define u16 uint16_t
|
||||
#define u8 uint8_t
|
||||
|
||||
#include "eventdns.h"
|
||||
|
||||
#define MAX_ADDRS 4 // maximum number of addresses from a single packet
|
||||
// which we bother recording
|
||||
|
||||
@ -502,7 +313,7 @@ static void server_request_free_answers(struct server_request *req);
|
||||
static void server_port_free(struct evdns_server_port *port);
|
||||
static void server_port_ready_callback(int fd, short events, void *arg);
|
||||
|
||||
#if defined(MS_WINDOWS) || defined(WIN32)
|
||||
#ifdef WIN32
|
||||
static int
|
||||
last_error(int sock)
|
||||
{
|
||||
@ -585,7 +396,7 @@ _evdns_log(int warn, const char *fmt, ...)
|
||||
if (!evdns_log_fn)
|
||||
return;
|
||||
va_start(args,fmt);
|
||||
#if defined(MS_WINDOWS) || defined(WIN32)
|
||||
#ifdef WIN32
|
||||
_vsnprintf(buf, sizeof(buf), fmt, args);
|
||||
#else
|
||||
vsnprintf(buf, sizeof(buf), fmt, args);
|
||||
@ -912,9 +723,9 @@ static inline int
|
||||
name_parse(u8 *packet, int length, int *idx, char *name_out, int name_out_len) {
|
||||
int name_end = -1;
|
||||
int j = *idx;
|
||||
#define GET32(x) do { if (j + 4 > length) return -1; memcpy(&_t32, packet + j, 4); j += 4; x = ntohl(_t32); } while(0);
|
||||
#define GET16(x) do { if (j + 2 > length) return -1; memcpy(&_t, packet + j, 2); j += 2; x = ntohs(_t); } while(0);
|
||||
#define GET8(x) do { if (j >= length) return -1; x = packet[j++]; } while(0);
|
||||
#define GET32(x) do { if (j + 4 > length) goto err; memcpy(&_t32, packet + j, 4); j += 4; x = ntohl(_t32); } while(0);
|
||||
#define GET16(x) do { if (j + 2 > length) goto err; memcpy(&_t, packet + j, 2); j += 2; x = ntohs(_t); } while(0);
|
||||
#define GET8(x) do { if (j >= length) goto err; x = packet[j++]; } while(0);
|
||||
|
||||
char *cp = name_out;
|
||||
const char *const end = name_out + name_out_len;
|
||||
@ -955,6 +766,8 @@ name_parse(u8 *packet, int length, int *idx, char *name_out, int name_out_len) {
|
||||
else
|
||||
*idx = name_end;
|
||||
return 0;
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
// parses a raw request from a nameserver.
|
||||
@ -968,7 +781,7 @@ reply_parse(u8 *packet, int length) {
|
||||
u16 trans_id, flags, questions, answers, authority, additional, datalength;
|
||||
u32 ttl, ttl_r = 0xffffffff;
|
||||
struct reply reply;
|
||||
struct request *req = NULL;
|
||||
struct request *req;
|
||||
unsigned int i;
|
||||
|
||||
GET16(trans_id);
|
||||
@ -977,15 +790,8 @@ reply_parse(u8 *packet, int length) {
|
||||
GET16(answers);
|
||||
GET16(authority);
|
||||
GET16(additional);
|
||||
(void) authority;
|
||||
(void) additional;
|
||||
|
||||
// This macro skips a name in the DNS reply.
|
||||
#define SKIP_NAME \
|
||||
do { tmp_name[0] = '\0'; \
|
||||
if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0) \
|
||||
return -1; \
|
||||
} while(0);
|
||||
(void) authority; /* suppress "unused variable" warnings. */
|
||||
(void) additional; /* suppress "unused variable" warnings. */
|
||||
|
||||
req = request_find_from_trans_id(trans_id);
|
||||
if (!req) return -1;
|
||||
@ -1001,6 +807,13 @@ reply_parse(u8 *packet, int length) {
|
||||
}
|
||||
// if (!answers) return; // must have an answer of some form
|
||||
|
||||
// This macro skips a name in the DNS reply.
|
||||
#define SKIP_NAME \
|
||||
do { tmp_name[0] = '\0'; \
|
||||
if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0) \
|
||||
goto err; \
|
||||
} while(0);
|
||||
|
||||
reply.type = req->request_type;
|
||||
|
||||
// skip over each question in the reply
|
||||
@ -1079,11 +892,9 @@ reply_parse(u8 *packet, int length) {
|
||||
|
||||
reply_handle(req, flags, ttl_r, &reply);
|
||||
return 0;
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
#undef SKIP_NAME
|
||||
#undef GET32
|
||||
#undef GET16
|
||||
#undef GET8
|
||||
|
||||
// Parse a raw request (packet,length) sent to a nameserver port (port) from
|
||||
// a DNS client (addr,addrlen), and if it's well-formed, call the corresponding
|
||||
@ -1095,9 +906,6 @@ request_parse(u8 *packet, int length, struct evdns_server_port *port, struct soc
|
||||
u16 _t; // used by the macros
|
||||
char tmp_name[256]; // used by the macros
|
||||
|
||||
#define GET16(x) do { if (j + 2 > length) goto err; memcpy(&_t, packet + j, 2); j += 2; x = ntohs(_t); } while(0);
|
||||
#define GET8(x) do { if (j >= length) goto err; x = packet[j++]; } while(0);
|
||||
|
||||
int i;
|
||||
u16 trans_id, flags, questions, answers, authority, additional;
|
||||
struct server_request *server_req = NULL;
|
||||
@ -1163,9 +971,12 @@ err:
|
||||
free(server_req);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#undef SKIP_NAME
|
||||
#undef GET32
|
||||
#undef GET16
|
||||
#undef GET8
|
||||
}
|
||||
|
||||
// Try to choose a strong transaction id which isn't already in flight
|
||||
static u16
|
||||
@ -1463,6 +1274,13 @@ dnsname_to_labels(u8 *const buf, size_t buf_len, off_t j,
|
||||
memcpy(buf + j, &_t, 2); \
|
||||
j += 2; \
|
||||
} while (0)
|
||||
#define APPEND32(x) do { \
|
||||
if (j + 4 > (off_t)buf_len) \
|
||||
goto overflow; \
|
||||
_t32 = htonl(x); \
|
||||
memcpy(buf + j, &_t32, 4); \
|
||||
j += 4; \
|
||||
} while (0)
|
||||
|
||||
if (name_len > 255) return -2;
|
||||
|
||||
@ -1522,20 +1340,12 @@ evdns_request_len(const int name_len) {
|
||||
//
|
||||
// Returns the amount of space used. Negative on error.
|
||||
static int
|
||||
evdns_request_data_build(const char *const name, const int name_len, const u16 trans_id,
|
||||
const u16 type, const u16 class,
|
||||
evdns_request_data_build(const char *const name, const int name_len,
|
||||
const u16 trans_id, const u16 type, const u16 class,
|
||||
u8 *const buf, size_t buf_len) {
|
||||
off_t j = 0; // current offset into buf
|
||||
u16 _t; // used by the macros
|
||||
|
||||
#define APPEND32(x) do { \
|
||||
if (j + 4 > (off_t)buf_len) \
|
||||
goto overflow; \
|
||||
_t32 = htonl(x); \
|
||||
memcpy(buf + j, &_t32, 4); \
|
||||
j += 4; \
|
||||
} while (0)
|
||||
|
||||
APPEND16(trans_id);
|
||||
APPEND16(0x0100); // standard query, recusion needed
|
||||
APPEND16(1); // one question
|
||||
@ -2031,8 +1841,8 @@ evdns_request_transmit(struct request *req) {
|
||||
evtimer_set(&req->timeout_event, evdns_request_timeout_callback, req);
|
||||
if (evtimer_add(&req->timeout_event, &global_timeout) < 0) {
|
||||
log(EVDNS_LOG_WARN,
|
||||
"Error from libevent when adding timer for "
|
||||
"request %lx", (unsigned long) req);
|
||||
"Error from libevent when adding timer for request %lx",
|
||||
(unsigned long) req);
|
||||
// ???? Do more?
|
||||
}
|
||||
req->tx_count++;
|
||||
@ -2159,6 +1969,7 @@ evdns_clear_nameservers_and_suspend(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// exported function
|
||||
int
|
||||
evdns_resume(void)
|
||||
@ -2190,7 +2001,7 @@ evdns_nameserver_add(unsigned long int address) {
|
||||
|
||||
ns->socket = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (ns->socket < 0) { err = 1; goto out1; }
|
||||
#if defined(MS_WINDOWS) || defined(WIN32)
|
||||
#ifdef WIN32
|
||||
{
|
||||
u_long nonblocking = 1;
|
||||
ioctlsocket(ns->socket, FIONBIO, &nonblocking);
|
||||
@ -2342,7 +2153,7 @@ int evdns_resolve_ipv4(const char *name, int flags,
|
||||
request_submit(req);
|
||||
return (0);
|
||||
} else {
|
||||
return search_request_new(TYPE_A, name, flags, callback, ptr);
|
||||
return (search_request_new(TYPE_A, name, flags, callback, ptr));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2358,7 +2169,7 @@ int evdns_resolve_ipv6(const char *name, int flags,
|
||||
request_submit(req);
|
||||
return (0);
|
||||
} else {
|
||||
return search_request_new(TYPE_AAAA, name, flags, callback, ptr);
|
||||
return (search_request_new(TYPE_AAAA, name, flags, callback, ptr));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2386,7 +2197,6 @@ int evdns_resolve_reverse_ipv6(struct in6_addr *in, int flags, evdns_callback_ty
|
||||
struct request *req;
|
||||
int i;
|
||||
assert(in);
|
||||
|
||||
cp = buf;
|
||||
for (i=0; i < 16; ++i) {
|
||||
u8 byte = in->s6_addr[i];
|
||||
@ -2404,6 +2214,7 @@ int evdns_resolve_reverse_ipv6(struct in6_addr *in, int flags, evdns_callback_ty
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// Search support
|
||||
//
|
||||
@ -2556,7 +2367,7 @@ search_make_new(const struct search_state *const state, int n, const char *const
|
||||
|
||||
// we ran off the end of the list and still didn't find the requested string
|
||||
abort();
|
||||
return NULL; /* unreachable. */
|
||||
return NULL; /* unreachable; stops warnings in some compilers. */
|
||||
}
|
||||
|
||||
static int
|
||||
@ -2806,7 +2617,7 @@ out1:
|
||||
return err;
|
||||
}
|
||||
|
||||
#if defined(MS_WINDOWS) || defined(WIN32)
|
||||
#ifdef WIN32
|
||||
// Add multiple nameservers from a space-or-comma-separated list.
|
||||
static int
|
||||
evdns_nameserver_ip_add_line(const char *ips) {
|
||||
@ -2861,7 +2672,6 @@ load_nameservers_with_getnetworkparams(void)
|
||||
|
||||
buf = malloc(size);
|
||||
if (!buf) { status = 4; goto done; }
|
||||
}
|
||||
fixed = buf;
|
||||
r = fn(fixed, &size);
|
||||
if (r != ERROR_SUCCESS && r != ERROR_BUFFER_OVERFLOW) {
|
||||
@ -2900,7 +2710,6 @@ load_nameservers_with_getnetworkparams(void)
|
||||
}
|
||||
|
||||
if (!added_any) {
|
||||
//should we ever get here? - mikec
|
||||
log(EVDNS_LOG_DEBUG, "No nameservers added.");
|
||||
status = -1;
|
||||
}
|
||||
@ -3006,7 +2815,7 @@ int
|
||||
evdns_init(void)
|
||||
{
|
||||
int res = 0;
|
||||
#if defined(MS_WINDOWS) || defined(WIN32)
|
||||
#ifdef WIN32
|
||||
evdns_config_windows_nameservers();
|
||||
#else
|
||||
res = evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf");
|
||||
|
@ -1,4 +1,12 @@
|
||||
/* This software is Public Domain. To view a copy of the public domain dedication,
|
||||
|
||||
/*
|
||||
* The original DNS code is due to Adam Langley with heavy
|
||||
* modifications by Nick Mathewson. Adam put his DNS software in the
|
||||
* public domain. You can find his original copyright below. Please,
|
||||
* aware that the code as part of libevent is governed by the 3-clause
|
||||
* BSD license above.
|
||||
*
|
||||
* This software is Public Domain. To view a copy of the public domain dedication,
|
||||
* visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
|
||||
* Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
|
||||
*
|
||||
@ -13,6 +21,193 @@
|
||||
* the source verbatim in their source distributions)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Welcome, gentle reader
|
||||
*
|
||||
* Async DNS lookups are really a whole lot harder than they should be,
|
||||
* mostly stemming from the fact that the libc resolver has never been
|
||||
* very good at them. Before you use this library you should see if libc
|
||||
* can do the job for you with the modern async call getaddrinfo_a
|
||||
* (see http://www.imperialviolet.org/page25.html#e498). Otherwise,
|
||||
* please continue.
|
||||
*
|
||||
* This code is based on libevent and you must call event_init before
|
||||
* any of the APIs in this file. You must also seed the OpenSSL random
|
||||
* source if you are using OpenSSL for ids (see below).
|
||||
*
|
||||
* This library is designed to be included and shipped with your source
|
||||
* code. You statically link with it. You should also test for the
|
||||
* existence of strtok_r and define HAVE_STRTOK_R if you have it.
|
||||
*
|
||||
* The DNS protocol requires a good source of id numbers and these
|
||||
* numbers should be unpredictable for spoofing reasons. There are
|
||||
* three methods for generating them here and you must define exactly
|
||||
* one of them. In increasing order of preference:
|
||||
*
|
||||
* DNS_USE_GETTIMEOFDAY_FOR_ID:
|
||||
* Using the bottom 16 bits of the usec result from gettimeofday. This
|
||||
* is a pretty poor solution but should work anywhere.
|
||||
* DNS_USE_CPU_CLOCK_FOR_ID:
|
||||
* Using the bottom 16 bits of the nsec result from the CPU's time
|
||||
* counter. This is better, but may not work everywhere. Requires
|
||||
* POSIX realtime support and you'll need to link against -lrt on
|
||||
* glibc systems at least.
|
||||
* DNS_USE_OPENSSL_FOR_ID:
|
||||
* Uses the OpenSSL RAND_bytes call to generate the data. You must
|
||||
* have seeded the pool before making any calls to this library.
|
||||
*
|
||||
* The library keeps track of the state of nameservers and will avoid
|
||||
* them when they go down. Otherwise it will round robin between them.
|
||||
*
|
||||
* Quick start guide:
|
||||
* #include "evdns.h"
|
||||
* void callback(int result, char type, int count, int ttl,
|
||||
* void *addresses, void *arg);
|
||||
* evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf");
|
||||
* evdns_resolve("www.hostname.com", 0, callback, NULL);
|
||||
*
|
||||
* When the lookup is complete the callback function is called. The
|
||||
* first argument will be one of the DNS_ERR_* defines in evdns.h.
|
||||
* Hopefully it will be DNS_ERR_NONE, in which case type will be
|
||||
* DNS_IPv4_A, count will be the number of IP addresses, ttl is the time
|
||||
* which the data can be cached for (in seconds), addresses will point
|
||||
* to an array of uint32_t's and arg will be whatever you passed to
|
||||
* evdns_resolve.
|
||||
*
|
||||
* Searching:
|
||||
*
|
||||
* In order for this library to be a good replacement for glibc's resolver it
|
||||
* supports searching. This involves setting a list of default domains, in
|
||||
* which names will be queried for. The number of dots in the query name
|
||||
* determines the order in which this list is used.
|
||||
*
|
||||
* Searching appears to be a single lookup from the point of view of the API,
|
||||
* although many DNS queries may be generated from a single call to
|
||||
* evdns_resolve. Searching can also drastically slow down the resolution
|
||||
* of names.
|
||||
*
|
||||
* To disable searching:
|
||||
* 1. Never set it up. If you never call evdns_resolv_conf_parse or
|
||||
* evdns_search_add then no searching will occur.
|
||||
*
|
||||
* 2. If you do call evdns_resolv_conf_parse then don't pass
|
||||
* DNS_OPTION_SEARCH (or DNS_OPTIONS_ALL, which implies it).
|
||||
*
|
||||
* 3. When calling evdns_resolve, pass the DNS_QUERY_NO_SEARCH flag.
|
||||
*
|
||||
* The order of searches depends on the number of dots in the name. If the
|
||||
* number is greater than the ndots setting then the names is first tried
|
||||
* globally. Otherwise each search domain is appended in turn.
|
||||
*
|
||||
* The ndots setting can either be set from a resolv.conf, or by calling
|
||||
* evdns_search_ndots_set.
|
||||
*
|
||||
* For example, with ndots set to 1 (the default) and a search domain list of
|
||||
* ["myhome.net"]:
|
||||
* Query: www
|
||||
* Order: www.myhome.net, www.
|
||||
*
|
||||
* Query: www.abc
|
||||
* Order: www.abc., www.abc.myhome.net
|
||||
*
|
||||
* API reference:
|
||||
*
|
||||
* int evdns_nameserver_add(unsigned long int address)
|
||||
* Add a nameserver. The address should be an IP address in
|
||||
* network byte order. The type of address is chosen so that
|
||||
* it matches in_addr.s_addr.
|
||||
* Returns non-zero on error.
|
||||
*
|
||||
* int evdns_nameserver_ip_add(const char *ip_as_string)
|
||||
* This wraps the above function by parsing a string as an IP
|
||||
* address and adds it as a nameserver.
|
||||
* Returns non-zero on error
|
||||
*
|
||||
* int evdns_resolve(const char *name, int flags,
|
||||
* evdns_callback_type callback,
|
||||
* void *ptr)
|
||||
* Resolve a name. The name parameter should be a DNS name.
|
||||
* The flags parameter should be 0, or DNS_QUERY_NO_SEARCH
|
||||
* which disables searching for this query. (see defn of
|
||||
* searching above).
|
||||
*
|
||||
* The callback argument is a function which is called when
|
||||
* this query completes and ptr is an argument which is passed
|
||||
* to that callback function.
|
||||
*
|
||||
* Returns non-zero on error
|
||||
*
|
||||
* void evdns_search_clear()
|
||||
* Clears the list of search domains
|
||||
*
|
||||
* void evdns_search_add(const char *domain)
|
||||
* Add a domain to the list of search domains
|
||||
*
|
||||
* void evdns_search_ndots_set(int ndots)
|
||||
* Set the number of dots which, when found in a name, causes
|
||||
* the first query to be without any search domain.
|
||||
*
|
||||
* int evdns_count_nameservers(void)
|
||||
* Return the number of configured nameservers (not necessarily the
|
||||
* number of running nameservers). This is useful for double-checking
|
||||
* whether our calls to the various nameserver configuration functions
|
||||
* have been successful.
|
||||
*
|
||||
* int evdns_clear_nameservers_and_suspend(void)
|
||||
* Remove all currently configured nameservers, and suspend all pending
|
||||
* resolves. Resolves will not necessarily be re-attempted until
|
||||
* evdns_resume() is called.
|
||||
*
|
||||
* int evdns_resume(void)
|
||||
* Re-attempt resolves left in limbo after an earlier call to
|
||||
* evdns_clear_nameservers_and_suspend().
|
||||
*
|
||||
* int evdns_config_windows_nameservers(void)
|
||||
* Attempt to configure a set of nameservers based on platform settings on
|
||||
* a win32 host. Preferentially tries to use GetNetworkParams; if that fails,
|
||||
* looks in the registry. Returns 0 on success, nonzero on failure.
|
||||
*
|
||||
* int evdns_resolv_conf_parse(int flags, const char *filename)
|
||||
* Parse a resolv.conf like file from the given filename.
|
||||
*
|
||||
* See the man page for resolv.conf for the format of this file.
|
||||
* The flags argument determines what information is parsed from
|
||||
* this file:
|
||||
* DNS_OPTION_SEARCH - domain, search and ndots options
|
||||
* DNS_OPTION_NAMESERVERS - nameserver lines
|
||||
* DNS_OPTION_MISC - timeout and attempts options
|
||||
* DNS_OPTIONS_ALL - all of the above
|
||||
* The following directives are not parsed from the file:
|
||||
* sortlist, rotate, no-check-names, inet6, debug
|
||||
*
|
||||
* Returns non-zero on error:
|
||||
* 0 no errors
|
||||
* 1 failed to open file
|
||||
* 2 failed to stat file
|
||||
* 3 file too large
|
||||
* 4 out of memory
|
||||
* 5 short read from file
|
||||
*
|
||||
* Internals:
|
||||
*
|
||||
* Requests are kept in two queues. The first is the inflight queue. In
|
||||
* this queue requests have an allocated transaction id and nameserver.
|
||||
* They will soon be transmitted if they haven't already been.
|
||||
*
|
||||
* The second is the waiting queue. The size of the inflight ring is
|
||||
* limited and all other requests wait in waiting queue for space. This
|
||||
* bounds the number of concurrent requests so that we don't flood the
|
||||
* nameserver. Several algorithms require a full walk of the inflight
|
||||
* queue and so bounding its size keeps thing going nicely under huge
|
||||
* (many thousands of requests) loads.
|
||||
*
|
||||
* If a nameserver loses too many requests it is considered down and we
|
||||
* try not to use it. After a while we send a probe to that nameserver
|
||||
* (a lookup for google.com) and, if it replies, we consider it working
|
||||
* again. If the nameserver fails a probe we wait longer to try again
|
||||
* with the next probe.
|
||||
*/
|
||||
|
||||
#ifndef EVENTDNS_H
|
||||
#define EVENTDNS_H
|
||||
|
||||
|
@ -10,4 +10,10 @@ typedef unsigned char u_char;
|
||||
#ifdef MS_WINDOWS
|
||||
#define inline __inline
|
||||
#endif
|
||||
#include "../common/torint.h"
|
||||
|
||||
#if defined(MS_WINDOWS) && !defined(WIN32)
|
||||
/* How did _this_ happen? */
|
||||
#define WIN32
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user