Commit 52713788 authored by Nick Mathewson's avatar Nick Mathewson 🌉
Browse files

r12080@catbus: nickm | 2007-03-04 21:40:55 -0500

 Remove dnsworkers and related code. there goes another 550 lines of code.


svn:r9736
parent 92f62b36
......@@ -11,6 +11,9 @@ Changes in version 0.2.0.1-alpha - 2007-??-??
This has been deprecated since 0.1.1, and warnings have been issued
since 0.1.2. When we encounter a v0 control message, we now send back
an error and close the connection.
- Remove the old "dns worker" server DNS code: it hasn't been default
since 0.1.2.2-alpha, and all the servers seem to be using the new
eventdns code.
Changes in version 0.1.2.10-rc - 2007-03-??
......
......@@ -19,18 +19,6 @@ AC_ARG_ENABLE(debug,
CFLAGS="$CFLAGS -g"
fi])
AC_ARG_ENABLE(eventdns,
AS_HELP_STRING(--enable-eventdns, enable asynchronous dns module),
[case "${enableval}" in
yes) eventdns=true ;;
no) eventdns=false ;;
*) AC_MSG_ERROR(bad value for --enable-eventdns) ;;
esac], [eventdns=true])
AM_CONDITIONAL(EVENTDNS, test x$eventdns = xtrue)
if test x$eventdns = xtrue; then
AC_DEFINE([USE_EVENTDNS], 1, "Define to 1 if we'll be using eventdns.c")
fi
AC_ARG_ENABLE(transparent,
AS_HELP_STRING(--disable-transparent, disable transparent proxy support),
[case "${enableval}" in
......@@ -44,14 +32,6 @@ AC_ARG_ENABLE(threads,
if test x$enable_threads = x; then
case $host in
*-*-netbsd* | *-*-openbsd* )
# Don't try multithreading on netbsd -- there is no threadsafe DNS
# lookup function there.
if test x$eventdns != xtrue; then
AC_MSG_NOTICE([You are running OpenBSD or NetBSD; I am assuming that
getaddrinfo is not threadsafe here, so I will disable threads.])
enable_threads="no"
fi ;;
*-*-solaris* )
# Don't try multithreading on solaris -- cpuworkers seem to lock.
AC_MSG_NOTICE([You are running Solaris; Sometimes threading makes
......
......@@ -4,19 +4,13 @@ noinst_PROGRAMS = test
bin_PROGRAMS = tor
if EVENTDNS
EVDNSSRC = eventdns.c
else
EVDNSSRC =
endif
tor_SOURCES = buffers.c circuitbuild.c circuitlist.c \
circuituse.c command.c config.c \
connection.c connection_edge.c connection_or.c control.c \
cpuworker.c directory.c dirserv.c dns.c hibernate.c main.c \
onion.c policies.c relay.c rendcommon.c rendclient.c rendmid.c \
rendservice.c rephist.c router.c routerlist.c routerparse.c \
$(EVDNSSRC) \
eventdns.c \
tor_main.c
tor_LDADD = ../common/libor.a ../common/libor-crypto.a -lz -lssl -lcrypto
......@@ -27,10 +21,10 @@ test_SOURCES = buffers.c circuitbuild.c circuitlist.c \
cpuworker.c directory.c dirserv.c dns.c hibernate.c main.c \
onion.c policies.c relay.c rendcommon.c rendclient.c rendmid.c \
rendservice.c rephist.c router.c routerlist.c routerparse.c \
$(EVDNSSRC) \
eventdns.c \
test.c
test_LDADD = ../common/libor.a ../common/libor-crypto.a -lz -lssl -lcrypto
noinst_HEADERS = or.h eventdns.h eventdns_tor.h eventdns.c
noinst_HEADERS = or.h eventdns.h eventdns_tor.h
......@@ -1001,13 +1001,10 @@ options_act(or_options_t *old_options)
cpuworkers_rotate();
if (dns_reset())
return -1;
}
#ifdef USE_EVENTDNS
else {
} else {
if (dns_reset())
return -1;
}
#endif
}
/* Check if we need to parse and add the EntryNodes config option. */
......@@ -2714,12 +2711,6 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (options->UseEntryGuards && ! options->NumEntryGuards)
REJECT("Cannot enable UseEntryGuards with NumEntryGuards set to 0");
#ifndef USE_EVENTDNS
if (options->ServerDNSResolvConfFile)
log(LOG_WARN, LD_CONFIG,
"ServerDNSResolvConfFile only works when eventdns support is enabled.");
#endif
if (check_nickname_list(options->ExitNodes, "ExitNodes", msg))
return -1;
if (check_nickname_list(options->EntryNodes, "EntryNodes", msg))
......
......@@ -51,7 +51,6 @@ conn_type_to_string(int type)
case CONN_TYPE_AP: return "Socks";
case CONN_TYPE_DIR_LISTENER: return "Directory listener";
case CONN_TYPE_DIR: return "Directory";
case CONN_TYPE_DNSWORKER: return "DNS worker";
case CONN_TYPE_CPUWORKER: return "CPU worker";
case CONN_TYPE_CONTROL_LISTENER: return "Control listener";
case CONN_TYPE_CONTROL: return "Control";
......@@ -118,12 +117,6 @@ conn_state_to_string(int type, int state)
case DIR_CONN_STATE_SERVER_WRITING: return "writing";
}
break;
case CONN_TYPE_DNSWORKER:
switch (state) {
case DNSWORKER_STATE_IDLE: return "idle";
case DNSWORKER_STATE_BUSY: return "busy";
}
break;
case CONN_TYPE_CPUWORKER:
switch (state) {
case CPUWORKER_STATE_IDLE: return "idle";
......@@ -496,11 +489,6 @@ connection_about_to_close_connection(connection_t *conn)
if (edge_conn->bridge_for_conn)
connection_dirserv_unlink_from_bridge(edge_conn->bridge_for_conn);
break;
case CONN_TYPE_DNSWORKER:
if (conn->state == DNSWORKER_STATE_BUSY) {
dns_cancel_pending_resolve(conn->address);
}
break;
}
}
......@@ -2242,8 +2230,6 @@ connection_process_inbuf(connection_t *conn, int package_partial)
package_partial);
case CONN_TYPE_DIR:
return connection_dir_process_inbuf(TO_DIR_CONN(conn));
case CONN_TYPE_DNSWORKER:
return connection_dns_process_inbuf(conn);
case CONN_TYPE_CPUWORKER:
return connection_cpu_process_inbuf(conn);
case CONN_TYPE_CONTROL:
......@@ -2289,8 +2275,6 @@ connection_finished_flushing(connection_t *conn)
return connection_edge_finished_flushing(TO_EDGE_CONN(conn));
case CONN_TYPE_DIR:
return connection_dir_finished_flushing(TO_DIR_CONN(conn));
case CONN_TYPE_DNSWORKER:
return connection_dns_finished_flushing(conn);
case CONN_TYPE_CPUWORKER:
return connection_cpu_finished_flushing(conn);
case CONN_TYPE_CONTROL:
......@@ -2339,8 +2323,6 @@ connection_reached_eof(connection_t *conn)
return connection_edge_reached_eof(TO_EDGE_CONN(conn));
case CONN_TYPE_DIR:
return connection_dir_reached_eof(TO_DIR_CONN(conn));
case CONN_TYPE_DNSWORKER:
return connection_dns_reached_eof(conn);
case CONN_TYPE_CPUWORKER:
return connection_cpu_reached_eof(conn);
case CONN_TYPE_CONTROL:
......@@ -2513,10 +2495,6 @@ assert_connection_ok(connection_t *conn, time_t now)
tor_assert(conn->purpose >= _DIR_PURPOSE_MIN);
tor_assert(conn->purpose <= _DIR_PURPOSE_MAX);
break;
case CONN_TYPE_DNSWORKER:
tor_assert(conn->state >= _DNSWORKER_STATE_MIN);
tor_assert(conn->state <= _DNSWORKER_STATE_MAX);
break;
case CONN_TYPE_CPUWORKER:
tor_assert(conn->state >= _CPUWORKER_STATE_MIN);
tor_assert(conn->state <= _CPUWORKER_STATE_MAX);
......
......@@ -8,32 +8,18 @@ const char dns_c_id[] =
/**
* \file dns.c
* \brief Implements a local cache for DNS results for Tor servers.
* We provide two asynchronous backend implementations:
* 1) A farm of 'DNS worker' threads or processes to perform DNS lookups for
* onion routers and cache the results.
* 2) A wrapper around Adam Langley's eventdns.c code, to send requests
* to the nameservers asynchronously.
* This is implemetned as a wrapper around Adam Langley's eventdns.c code.
* (We can't just use gethostbyname() and friends because we really need to
* be nonblocking.)
**/
#include "or.h"
#include "../common/ht.h"
#ifdef USE_EVENTDNS
#include "eventdns.h"
#endif
/** Longest hostname we're willing to resolve. */
#define MAX_ADDRESSLEN 256
/** Maximum DNS processes to spawn. */
#define MAX_DNSWORKERS 100
/** Minimum DNS processes to spawn. */
#define MIN_DNSWORKERS 3
/** If more than this many processes are idle, shut down the extras. */
#define MAX_IDLE_DNSWORKERS 10
/** How long will we wait for an answer from the resolver before we decide
* that the resolver is wedged? */
#define RESOLVE_MAX_TIMEOUT 300
......@@ -44,14 +30,6 @@ const char dns_c_id[] =
#define DNS_RESOLVE_FAILED_PERMANENT 2
#define DNS_RESOLVE_SUCCEEDED 3
#ifndef USE_EVENTDNS
/** How many dnsworkers we have running right now. */
static int num_dnsworkers=0;
/** How many of the running dnsworkers have an assigned task right now. */
static int num_dnsworkers_busy=0;
/** When did we last rotate the dnsworkers? */
static time_t last_rotation_time=0;
#else
/** Have we currently configured nameservers with eventdns? */
static int nameservers_configured = 0;
/** What was the resolv_conf fname we last used when configuring the
......@@ -60,7 +38,6 @@ static char *resolv_conf_fname = NULL;
/** What was the mtime on the resolv.conf file we last used when configuring
* the nameservers? Used to check whether we need to reconfigure. */
static time_t resolv_conf_mtime = 0;
#endif
/** Linked list of connections waiting for a DNS answer. */
typedef struct pending_connection_t {
......@@ -118,16 +95,9 @@ static void dns_found_answer(const char *address, int is_reverse,
static void send_resolved_cell(edge_connection_t *conn, or_circuit_t *circ,
uint8_t answer_type);
static int launch_resolve(edge_connection_t *exitconn, or_circuit_t *circ);
#ifndef USE_EVENTDNS
static void dnsworkers_rotate(void);
static void dnsworker_main(void *data);
static int spawn_dnsworker(void);
static int spawn_enough_dnsworkers(void);
#else
static void add_wildcarded_test_address(const char *address);
static int configure_nameservers(int force);
static int answer_is_wildcarded(const char *ip);
#endif
#ifdef DEBUG_DNS_CACHE
static void _assert_cache_ok(void);
#define assert_cache_ok() _assert_cache_ok()
......@@ -168,7 +138,6 @@ init_cache_map(void)
HT_INIT(cache_map, &cache_root);
}
#ifdef USE_EVENTDNS
/** Helper: called by eventdns when eventdns wants to log something. */
static void
evdns_log_cb(int warn, const char *msg)
......@@ -208,19 +177,14 @@ evdns_log_cb(int warn, const char *msg)
}
log(severity, LD_EXIT, "eventdns: %s", msg);
}
#endif
/** Initialize the DNS subsystem; called by the OR process. */
int
dns_init(void)
{
init_cache_map();
#ifdef USE_EVENTDNS
if (server_mode(get_options()))
return configure_nameservers(1);
#else
dnsworkers_rotate();
#endif
return 0;
}
......@@ -229,7 +193,6 @@ dns_init(void)
int
dns_reset(void)
{
#ifdef USE_EVENTDNS
or_options_t *options = get_options();
if (! server_mode(options)) {
evdns_clear_nameservers_and_suspend();
......@@ -241,9 +204,6 @@ dns_reset(void)
if (configure_nameservers(0) < 0)
return -1;
}
#else
dnsworkers_rotate();
#endif
return 0;
}
......@@ -338,9 +298,7 @@ dns_free_all(void)
if (cached_resolve_pqueue)
smartlist_free(cached_resolve_pqueue);
cached_resolve_pqueue = NULL;
#ifdef USE_EVENTDNS
tor_free(resolv_conf_fname);
#endif
}
/** Remove every cached_resolve whose <b>expire</b> time is before <b>now</b>
......@@ -635,7 +593,6 @@ dns_resolve(edge_connection_t *exitconn, or_circuit_t *oncirc)
if (r == 1)
is_reverse = 1;
#ifdef USE_EVENTDNS
if (!is_reverse || !is_resolve) {
if (!is_reverse)
log_info(LD_EXIT, "Bad .in-addr.arpa address \"%s\"; sending error.",
......@@ -645,12 +602,6 @@ dns_resolve(edge_connection_t *exitconn, or_circuit_t *oncirc)
"Attempt to connect to a .in-addr.arpa address \"%s\"; "
"sending error.",
escaped_safe_str(exitconn->_base.address));
#else
if (1) {
log_info(LD_PROTOCOL, "Dnsworker code does not support in-addr.arpa "
"domain, but received a request for \"%s\"; sending error.",
escaped_safe_str(exitconn->_base.address));
#endif
if (exitconn->_base.purpose == EXIT_PURPOSE_RESOLVE)
send_resolved_cell(exitconn, oncirc, RESOLVED_TYPE_ERROR);
......@@ -1062,412 +1013,6 @@ dns_found_answer(const char *address, int is_reverse, uint32_t addr,
assert_cache_ok();
}
#ifndef USE_EVENTDNS
/** Find or spawn a dns worker process to handle resolving
* <b>exitconn</b>-\>address; tell that dns worker to begin resolving.
*/
static int
launch_resolve(edge_connection_t *exitconn, or_circuit_t *circ)
{
connection_t *dnsconn;
unsigned char len;
tor_assert(exitconn->_base.state == EXIT_CONN_STATE_RESOLVING);
assert_connection_ok(TO_CONN(exitconn), 0);
tor_assert(exitconn->_base.s == -1);
/* respawn here, to be sure there are enough */
if (spawn_enough_dnsworkers() < 0) {
goto err;
}
dnsconn = connection_get_by_type_state(CONN_TYPE_DNSWORKER,
DNSWORKER_STATE_IDLE);
if (!dnsconn) {
log_warn(LD_EXIT,"no idle dns workers. Failing.");
if (exitconn->_base.purpose == EXIT_PURPOSE_RESOLVE)
send_resolved_cell(exitconn, circ, RESOLVED_TYPE_ERROR_TRANSIENT);
goto err;
}
log_debug(LD_EXIT,
"Connection (fd %d) needs to resolve %s; assigning "
"to DNSWorker (fd %d)", exitconn->_base.s,
escaped_safe_str(exitconn->_base.address), dnsconn->s);
tor_free(dnsconn->address);
dnsconn->address = tor_strdup(exitconn->_base.address);
dnsconn->state = DNSWORKER_STATE_BUSY;
/* touch the lastwritten timestamp, since that's how we check to
* see how long it's been since we asked the question, and sometimes
* we check before the first call to connection_handle_write(). */
dnsconn->timestamp_lastwritten = time(NULL);
num_dnsworkers_busy++;
len = strlen(dnsconn->address);
connection_write_to_buf((char*)&len, 1, dnsconn);
connection_write_to_buf(dnsconn->address, len, dnsconn);
return 0;
err:
/* also sends end and frees */
dns_cancel_pending_resolve(exitconn->_base.address);
return -1;
}
/******************************************************************/
/*
* Connection between OR and dnsworker
*/
/** Write handler: called when we've pushed a request to a dnsworker. */
int
connection_dns_finished_flushing(connection_t *conn)
{
tor_assert(conn);
tor_assert(conn->type == CONN_TYPE_DNSWORKER);
connection_stop_writing(conn);
return 0;
}
/** Called when a connection to a dnsworker hits an EOF; this only happens
* when a dnsworker dies unexpectedly. */
int
connection_dns_reached_eof(connection_t *conn)
{
log_warn(LD_EXIT,"Read eof. DNS worker died unexpectedly.");
if (conn->state == DNSWORKER_STATE_BUSY) {
/* don't cancel the resolve here -- it would be cancelled in
* connection_about_to_close_connection(), since conn is still
* in state BUSY
*/
num_dnsworkers_busy--;
}
num_dnsworkers--;
connection_mark_for_close(conn);
return 0;
}
/** Read handler: called when we get data from a dnsworker. See
* if we have a complete answer. If so, call dns_found_answer on the
* result. If not, wait. Returns 0. */
int
connection_dns_process_inbuf(connection_t *conn)
{
char success;
uint32_t addr;
int ttl;
tor_assert(conn);
tor_assert(conn->type == CONN_TYPE_DNSWORKER);
if (conn->state != DNSWORKER_STATE_BUSY && buf_datalen(conn->inbuf)) {
log_warn(LD_BUG,
"read data (%d bytes) from an idle dns worker (fd %d, "
"address %s). Please report.", (int)buf_datalen(conn->inbuf),
conn->s, escaped_safe_str(conn->address));
tor_fragile_assert();
/* Pull it off the buffer anyway, or it will just stay there.
* Keep pulling things off because sometimes we get several
* answers at once (!). */
while (buf_datalen(conn->inbuf)) {
connection_fetch_from_buf(&success,1,conn);
connection_fetch_from_buf((char *)&addr,sizeof(uint32_t),conn);
log_warn(LD_EXIT,"Discarding idle dns answer (success %d, addr %d.)",
success, addr);
}
return 0;
}
if (buf_datalen(conn->inbuf) < 5) /* entire answer available? */
return 0; /* not yet */
tor_assert(conn->state == DNSWORKER_STATE_BUSY);
tor_assert(buf_datalen(conn->inbuf) == 5);
connection_fetch_from_buf(&success,1,conn);
connection_fetch_from_buf((char *)&addr,sizeof(uint32_t),conn);
log_debug(LD_EXIT, "DNSWorker (fd %d) returned answer for %s",
conn->s, escaped_safe_str(conn->address));
tor_assert(success >= DNS_RESOLVE_FAILED_TRANSIENT);
tor_assert(success <= DNS_RESOLVE_SUCCEEDED);
ttl = (success == DNS_RESOLVE_FAILED_TRANSIENT) ? 0 : MAX_DNS_ENTRY_AGE;
dns_found_answer(conn->address, 0, ntohl(addr), NULL, success, ttl);
tor_free(conn->address);
conn->address = tor_strdup("<idle>");
conn->state = DNSWORKER_STATE_IDLE;
num_dnsworkers_busy--;
if (conn->timestamp_created < last_rotation_time) {
connection_mark_for_close(conn);
num_dnsworkers--;
spawn_enough_dnsworkers();
}
return 0;
}
/** Close and re-open all idle dnsworkers; schedule busy ones to be closed
* and re-opened once they're no longer busy.
**/
static void
dnsworkers_rotate(void)
{
connection_t *dnsconn;
while ((dnsconn = connection_get_by_type_state(CONN_TYPE_DNSWORKER,
DNSWORKER_STATE_IDLE))) {
connection_mark_for_close(dnsconn);
num_dnsworkers--;
}
last_rotation_time = time(NULL);
if (server_mode(get_options()))
spawn_enough_dnsworkers();
}
/** Implementation for DNS workers; this code runs in a separate
* execution context. It takes as its argument an fdarray as returned
* by socketpair(), and communicates via fdarray[1]. The protocol is
* as follows:
* - The OR says:
* - ADDRESSLEN [1 byte]
* - ADDRESS [ADDRESSLEN bytes]
* - The DNS worker does the lookup, and replies:
* - OUTCOME [1 byte]
* - IP [4 bytes]
*
* OUTCOME is one of DNS_RESOLVE_{FAILED_TRANSIENT|FAILED_PERMANENT|SUCCEEDED}.
* IP is in host order.
*
* The dnsworker runs indefinitely, until its connection is closed or an error
* occurs.
*/
static void
dnsworker_main(void *data)
{
char address[MAX_ADDRESSLEN+1]; /* Plus a byte for a final '.' */
unsigned char address_len;
char *log_address;
char answer[5];
uint32_t ip;
int *fdarray = data;
int fd;
int result;
int search = get_options()->ServerDNSSearchDomains;
/* log_fn(LOG_NOTICE,"After spawn: fdarray @%d has %d:%d", (int)fdarray,
* fdarray[0],fdarray[1]); */
fd = fdarray[1]; /* this side is ours */
#ifndef TOR_IS_MULTITHREADED
tor_close_socket(fdarray[0]); /* this is the side of the socketpair the
* parent uses */
tor_free_all(1); /* so the child doesn't hold the parent's fd's open */
handle_signals(0); /* ignore interrupts from the keyboard, etc */
#endif
tor_free(data);
for (;;) {
int r;
if ((r = recv(fd, &address_len, 1, 0)) != 1) {
if (r == 0) {
log_info(LD_EXIT,"DNS worker exiting because Tor process closed "
"connection (either pruned idle dnsworker or died).");
} else {
log_info(LD_EXIT,"DNS worker exiting because of error on connection "
"to Tor process.");
log_info(LD_EXIT,"(Error on %d was %s)", fd,
tor_socket_strerror(tor_socket_errno(fd)));
}
tor_close_socket(fd);
crypto_thread_cleanup();
spawn_exit();
}
if (address_len && read_all(fd, address, address_len, 1) != address_len) {
log_err(LD_BUG,"read hostname failed. Child exiting.");
tor_close_socket(fd);
crypto_thread_cleanup();
spawn_exit();
}
/* Add a period to prevent local domain search, and NUL-terminate. */
if (address[address_len-1] != '.' && !search) {
address[address_len] = '.';
address[address_len+1] = '\0';
} else {
address[address_len] = '\0';
}
log_address = esc_for_log(safe_str(address));
result = tor_lookup_hostname(address, &ip);
/* Make 0.0.0.0 an error, so that we can use "0" to mean "no addr") */
if (!ip)
result = -1;
switch (result) {
case 1:
/* XXX result can never be 1, because we set it to -1 above on error */
log_info(LD_NET,"Could not resolve dest addr %s (transient)",
log_address);
answer[0] = DNS_RESOLVE_FAILED_TRANSIENT;
break;
case -1:
log_info(LD_NET,"Could not resolve dest addr %s (permanent)",
log_address);
answer[0] = DNS_RESOLVE_FAILED_PERMANENT;
break;
case 0:
log_info(LD_NET,"Resolved address %s", log_address);
answer[0] = DNS_RESOLVE_SUCCEEDED;
break;
}
tor_free(log_address);
set_uint32(answer+1, ip);
if (write_all(fd, answer, 5, 1) != 5) {
log_err(LD_NET,"writing answer failed. Child exiting.");
tor_close_socket(fd);
crypto_thread_cleanup();
spawn_exit();
}
}
}
/** Launch a new DNS worker; return 0 on success, -1 on failure.
*/
static int
spawn_dnsworker(void)
{
int *fdarray;
int fd;
connection_t *conn;
int err;
fdarray = tor_malloc(sizeof(int)*2);
if ((err = tor_socketpair(AF_UNIX, SOCK_STREAM, 0, fdarray)) < 0) {
log_warn(LD_NET, "Couldn't construct socketpair for dns worker: %s",
tor_socket_strerror(-err));
tor_free(fdarray);
return -1;
}
tor_assert(fdarray[0] >= 0);
tor_assert(fdarray[1] >= 0);
/* log_fn(LOG_NOTICE,"Before spawn: fdarray @%d has %d:%d",
(int)fdarray, fdarray[0],fdarray[1]); */
fd = fdarray[0]; /* We copy this out here, since dnsworker_main may free
* fdarray */
spawn_func((void*) dnsworker_main, (void*)fdarray);
log_debug(LD_EXIT,"just spawned a dns worker.");
#ifndef TOR_IS_MULTITHREADED
tor_close_socket(fdarray[1]); /* don't need the worker's side of the pipe */
tor_free(fdarray);
#endif
conn = connection_new(CONN_TYPE_DNSWORKER);
set_socket_nonblocking(fd);
/* set up conn so it's got all the data we need to remember */
conn->s = fd;
conn->address = tor_strdup("<unused>");
if (connection_add(conn) < 0) { /* no space, forget it */
log_warn(LD_NET,"connection_add for dnsworker failed. Giving up.");
connection_free(conn); /* this closes fd */