Merge remote branch 'origin/master' into bug2046

This commit is contained in:
Steven Murdoch
2011-08-18 18:42:02 +01:00
63 changed files with 5948 additions and 3670 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
noinst_LIBRARIES = libor.a libor-crypto.a libor-event.a
EXTRA_DIST = common_sha1.i sha256.c
EXTRA_DIST = common_sha1.i sha256.c Makefile.nmake
#CFLAGS = -Wall -Wpointer-arith -O2
+20
View File
@@ -0,0 +1,20 @@
all: libor.lib libor-crypto.lib libor-event.lib
CFLAGS = /I ..\win32 /I ..\..\..\build-alpha\include
LIBOR_OBJECTS = address.obj compat.obj container.obj di_ops.obj \
log.obj memarea.obj mempool.obj procmon.obj util.obj \
util_codedigest.obj
LIBOR_CRYPTO_OBJECTS = aes.obj crypto.obj torgzip.obj tortls.obj
LIBOR_EVENT_OBJECTS = compat_libevent.obj
libor.lib: $(LIBOR_OBJECTS)
lib $(LIBOR_OBJECTS) /out:libor.lib
libor-crypto.lib: $(LIBOR_CRYPTO_OBJECTS)
lib $(LIBOR_CRYPTO_OBJECTS) /out:libor-crypto.lib
libor-event.lib: $(LIBOR_EVENT_OBJECTS)
lib $(LIBOR_EVENT_OBJECTS) /out:libor-event.lib
+4 -2
View File
@@ -958,8 +958,10 @@ fmt_addr(const tor_addr_t *addr)
{
static char buf[TOR_ADDR_BUF_LEN];
if (!addr) return "<null>";
tor_addr_to_str(buf, addr, sizeof(buf), 0);
return buf;
if (tor_addr_to_str(buf, addr, sizeof(buf), 0))
return buf;
else
return "???";
}
/** Like fmt_addr(), but takes <b>addr</b> as a host-order IPv4
+1 -1
View File
@@ -401,7 +401,7 @@ typedef int socklen_t;
#ifdef MS_WINDOWS
#define tor_socket_t intptr_t
#define SOCKET_OK(s) ((s) != INVALID_SOCKET)
#define SOCKET_OK(s) ((unsigned)(s) != INVALID_SOCKET)
#else
#define tor_socket_t int
#define SOCKET_OK(s) ((s) >= 0)
+4 -1
View File
@@ -19,6 +19,7 @@
#ifdef HAVE_EVENT2_EVENT_H
#include <event2/event.h>
#include <event2/thread.h>
#else
#include <event.h>
#endif
@@ -183,8 +184,10 @@ tor_libevent_initialize(tor_libevent_cfg *torcfg)
struct event_config *cfg = event_config_new();
#if defined(MS_WINDOWS) && defined(USE_BUFFEREVENTS)
if (! torcfg->disable_iocp)
if (! torcfg->disable_iocp) {
evthread_use_windows_threads();
event_config_set_flag(cfg, EVENT_BASE_FLAG_STARTUP_IOCP);
}
#endif
#if defined(LIBEVENT_VERSION_NUMBER) && LIBEVENT_VERSION_NUMBER >= V(2,0,7)
-4
View File
@@ -43,11 +43,7 @@
#define off64_t int64_t
#endif
#ifdef _MSC_VER
#include "..\..\contrib\zlib\zlib.h"
#else
#include <zlib.h>
#endif
/** Set to 1 if zlib is a version that supports gzip; set to 0 if it doesn't;
* set to -1 if we haven't checked yet. */
+9
View File
@@ -111,6 +111,15 @@ typedef signed int int32_t;
typedef unsigned int uint32_t;
#define HAVE_UINT32_T
#endif
#ifndef UINT16_MAX
#define UINT16_MAX 0xffffu
#endif
#ifndef INT16_MAX
#define INT16_MAX 0x7fff
#endif
#ifndef INT16_MIN
#define INT16_MIN (-INT16_MAX-1)
#endif
#ifndef UINT32_MAX
#define UINT32_MAX 0xffffffffu
#endif
+16
View File
@@ -273,6 +273,22 @@ tor_tls_log_one_error(tor_tls_t *tls, unsigned long err,
addr = tls ? tls->address : NULL;
/* Some errors are known-benign, meaning they are the fault of the other
* side of the connection. The caller doesn't know this, so override the
* priority for those cases. */
switch (ERR_GET_REASON(err)) {
case SSL_R_HTTP_REQUEST:
case SSL_R_HTTPS_PROXY_REQUEST:
case SSL_R_RECORD_LENGTH_MISMATCH:
case SSL_R_RECORD_TOO_LARGE:
case SSL_R_UNKNOWN_PROTOCOL:
case SSL_R_UNSUPPORTED_PROTOCOL:
severity = LOG_INFO;
break;
default:
break;
}
msg = (const char*)ERR_reason_error_string(err);
lib = (const char*)ERR_lib_error_string(err);
func = (const char*)ERR_func_error_string(err);
+72 -3
View File
@@ -14,6 +14,9 @@
#define _GNU_SOURCE
#include "orconfig.h"
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#define UTIL_PRIVATE
#include "util.h"
#include "torlog.h"
@@ -68,9 +71,6 @@
#ifdef HAVE_SYS_FCNTL_H
#include <sys/fcntl.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_TIME_H
#include <time.h>
#endif
@@ -412,6 +412,32 @@ round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor)
return number;
}
/** Return the number of bits set in <b>v</b>. */
int
n_bits_set_u8(uint8_t v)
{
static const int nybble_table[] = {
0, /* 0000 */
1, /* 0001 */
1, /* 0010 */
2, /* 0011 */
1, /* 0100 */
2, /* 0101 */
2, /* 0110 */
3, /* 0111 */
1, /* 1000 */
2, /* 1001 */
2, /* 1010 */
3, /* 1011 */
2, /* 1100 */
3, /* 1101 */
3, /* 1110 */
4, /* 1111 */
};
return nybble_table[v & 15] + nybble_table[v>>4];
}
/* =====
* String manipulation
* ===== */
@@ -495,6 +521,23 @@ tor_strisnonupper(const char *s)
return 1;
}
/** As strcmp, except that either string may be NULL. The NULL string is
* considered to be before any non-NULL string. */
int
strcmp_opt(const char *s1, const char *s2)
{
if (!s1) {
if (!s2)
return 0;
else
return -1;
} else if (!s2) {
return 1;
} else {
return strcmp(s1, s2);
}
}
/** Compares the first strlen(s2) characters of s1 with s2. Returns as for
* strcmp.
*/
@@ -1693,6 +1736,8 @@ check_private_dir(const char *dirname, cpd_check_t check,
struct passwd *pw = NULL;
uid_t running_uid;
gid_t running_gid;
#else
(void)effective_user;
#endif
tor_assert(dirname);
@@ -2636,6 +2681,30 @@ tor_sscanf(const char *buf, const char *pattern, ...)
return r;
}
/** Append the string produced by tor_asprintf(<b>pattern</b>, <b>...</b>)
* to <b>sl</b>. */
void
smartlist_asprintf_add(struct smartlist_t *sl, const char *pattern, ...)
{
va_list ap;
va_start(ap, pattern);
smartlist_vasprintf_add(sl, pattern, ap);
va_end(ap);
}
/** va_list-based backend of smartlist_asprintf_add. */
void
smartlist_vasprintf_add(struct smartlist_t *sl, const char *pattern,
va_list args)
{
char *str = NULL;
tor_vasprintf(&str, pattern, args);
tor_assert(str != NULL);
smartlist_add(sl, str);
}
/** Return a new list containing the filenames in the directory <b>dirname</b>.
* Return NULL on error or if <b>dirname</b> is not a directory.
*/
+7
View File
@@ -160,6 +160,7 @@ uint64_t round_to_power_of_2(uint64_t u64);
unsigned round_to_next_multiple_of(unsigned number, unsigned divisor);
uint32_t round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor);
uint64_t round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor);
int n_bits_set_u8(uint8_t v);
/* Compute the CEIL of <b>a</b> divided by <b>b</b>, for nonnegative <b>a</b>
* and positive <b>b</b>. Works on integer types only. Not defined if a+b can
@@ -174,6 +175,7 @@ void tor_strlower(char *s) ATTR_NONNULL((1));
void tor_strupper(char *s) ATTR_NONNULL((1));
int tor_strisprint(const char *s) ATTR_PURE ATTR_NONNULL((1));
int tor_strisnonupper(const char *s) ATTR_PURE ATTR_NONNULL((1));
int strcmp_opt(const char *s1, const char *s2) ATTR_PURE;
int strcmpstart(const char *s1, const char *s2) ATTR_PURE ATTR_NONNULL((1,2));
int strcmp_len(const char *s1, const char *s2, size_t len)
ATTR_PURE ATTR_NONNULL((1,2));
@@ -218,6 +220,11 @@ int tor_sscanf(const char *buf, const char *pattern, ...)
#endif
;
void smartlist_asprintf_add(struct smartlist_t *sl, const char *pattern, ...)
CHECK_PRINTF(2, 3);
void smartlist_vasprintf_add(struct smartlist_t *sl, const char *pattern,
va_list args);
int hex_decode_digit(char c);
void base16_encode(char *dest, size_t destlen, const char *src, size_t srclen);
int base16_decode(char *dest, size_t destlen, const char *src, size_t srclen);
+3232 -2959
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -7,7 +7,7 @@ else
tor_platform_source=
endif
EXTRA_DIST=ntmain.c or_sha1.i
EXTRA_DIST=ntmain.c or_sha1.i Makefile.nmake
if USE_EXTERNAL_EVDNS
evdns_source=
+28
View File
@@ -0,0 +1,28 @@
all: tor.exe
CFLAGS = /I ..\win32 /I ..\..\..\build-alpha\include /I ..\common
LIBS = ..\..\..\build-alpha\lib\libevent.a \
..\..\..\build-alpha\lib\libcrypto.a \
..\..\..\build-alpha\lib\libssl.a \
..\..\..\build-alpha\lib\libz.a \
ws2_32.lib advapi32.lib shell32.lib
LIBTOR_OBJECTS = buffers.obj circuitbuild.obj circuitlist.obj circuituse.obj \
command.obj config.obj connection.obj connection_edge.obj \
connection_or.obj control.obj cpuworker.obj directory.obj \
dirserv.obj dirvote.obj dns.obj dnsserv.obj geoip.obj \
hibernate.obj main.obj microdesc.obj networkstatus.obj \
nodelist.obj onion.obj policies.obj reasons.obj relay.obj \
rendclient.obj rendcommon.obj rendmid.obj rendservice.obj \
rephist.obj router.obj routerlist.obj routerparse.obj status.obj \
config_codedigest.obj ntmain.obj
libtor.lib: $(LIBTOR_OBJECTS)
lib $(LIBTOR_OBJECTS) /out:libtor.lib
tor.exe: libtor.lib tor_main.obj
$(CC) $(CFLAGS) $(LIBS) libtor.lib ..\common\*.lib tor_main.obj
clean:
del $(LIBTOR_OBJECTS) *.lib tor.exe
+88 -22
View File
@@ -557,6 +557,39 @@ buf_free(buf_t *buf)
tor_free(buf);
}
/** Return a new copy of <b>in_chunk</b> */
static chunk_t *
chunk_copy(const chunk_t *in_chunk)
{
chunk_t *newch = tor_memdup(in_chunk, CHUNK_ALLOC_SIZE(in_chunk->memlen));
newch->next = NULL;
if (in_chunk->data) {
off_t offset = in_chunk->data - in_chunk->mem;
newch->data = newch->mem + offset;
}
return newch;
}
/** Return a new copy of <b>buf</b> */
buf_t *
buf_copy(const buf_t *buf)
{
chunk_t *ch;
buf_t *out = buf_new();
out->default_chunk_size = buf->default_chunk_size;
for (ch = buf->head; ch; ch = ch->next) {
chunk_t *newch = chunk_copy(ch);
if (out->tail) {
out->tail->next = newch;
out->tail = newch;
} else {
out->head = out->tail = newch;
}
}
out->datalen = buf->datalen;
return out;
}
/** Append a new chunk with enough capacity to hold <b>capacity</b> bytes to
* the tail of <b>buf</b>. If <b>capped</b>, don't allocate a chunk bigger
* than MAX_CHUNK_ALLOC. */
@@ -1021,13 +1054,13 @@ fetch_var_cell_from_buf(buf_t *buf, var_cell_t **out, int linkproto)
#ifdef USE_BUFFEREVENTS
/** Try to read <b>n</b> bytes from <b>buf</b> at <b>pos</b> (which may be
* NULL for the start of the buffer), copying the data only if necessary. Set
* *<b>data</b> to a pointer to the desired bytes. Set <b>free_out</b> to 1
* *<b>data_out</b> to a pointer to the desired bytes. Set <b>free_out</b> to 1
* if we needed to malloc *<b>data</b> because the original bytes were
* noncontiguous; 0 otherwise. Return the number of bytes actually available
* at <b>data</b>.
* at *<b>data_out</b>.
*/
static ssize_t
inspect_evbuffer(struct evbuffer *buf, char **data, size_t n, int *free_out,
inspect_evbuffer(struct evbuffer *buf, char **data_out, size_t n, int *free_out,
struct evbuffer_ptr *pos)
{
int n_vecs, i;
@@ -1042,25 +1075,15 @@ inspect_evbuffer(struct evbuffer *buf, char **data, size_t n, int *free_out,
struct evbuffer_iovec v;
i = evbuffer_peek(buf, n, pos, &v, 1);
tor_assert(i == 1);
*data = v.iov_base;
*data_out = v.iov_base;
*free_out = 0;
return v.iov_len;
} else {
struct evbuffer_iovec *vecs =
tor_malloc(sizeof(struct evbuffer_iovec)*n_vecs);
size_t copied = 0;
i = evbuffer_peek(buf, n, NULL, vecs, n_vecs);
tor_assert(i == n_vecs);
*data = tor_malloc(n);
for (i=0; i < n_vecs; ++i) {
size_t copy = n - copied;
if (copy > vecs[i].iov_len)
copy = vecs[i].iov_len;
tor_assert(copied+copy <= n);
memcpy(data+copied, vecs[i].iov_base, copy);
copied += copy;
}
ev_ssize_t copied;
*data_out = tor_malloc(n);
*free_out = 1;
copied = evbuffer_copyout(buf, *data_out, n);
tor_assert(copied >= 0 && (size_t)copied == n);
return copied;
}
}
@@ -1499,8 +1522,14 @@ socks_request_free(socks_request_t *req)
{
if (!req)
return;
tor_free(req->username);
tor_free(req->password);
if (req->username) {
memset(req->username, 0x10, req->usernamelen);
tor_free(req->username);
}
if (req->password) {
memset(req->password, 0x04, req->passwordlen);
tor_free(req->password);
}
memset(req, 0xCC, sizeof(socks_request_t));
tor_free(req);
}
@@ -1581,12 +1610,12 @@ fetch_from_evbuffer_socks(struct evbuffer *buf, socks_request_t *req,
*/
struct evbuffer_iovec v;
int i;
want_length = evbuffer_get_contiguous_space(buf);
n_drain = 0;
i = evbuffer_peek(buf, want_length, NULL, &v, 1);
i = evbuffer_peek(buf, -1, NULL, &v, 1);
tor_assert(i == 1);
data = v.iov_base;
datalen = v.iov_len;
want_length = 0;
res = parse_socks(data, datalen, req, log_sockstype,
safe_socks, &n_drain, &want_length);
@@ -2374,6 +2403,43 @@ write_to_evbuffer_zlib(struct evbuffer *buf, tor_zlib_state_t *state,
}
#endif
/** Set *<b>output</b> to contain a copy of the data in *<b>input</b> */
int
generic_buffer_set_to_copy(generic_buffer_t **output,
const generic_buffer_t *input)
{
#ifdef USE_BUFFEREVENTS
struct evbuffer_ptr ptr;
size_t remaining = evbuffer_get_length(input);
if (*output) {
evbuffer_drain(*output, evbuffer_get_length(*output));
} else {
if (!(*output = evbuffer_new()))
return -1;
}
evbuffer_ptr_set((struct evbuffer*)input, &ptr, 0, EVBUFFER_PTR_SET);
while (remaining) {
struct evbuffer_iovec v[4];
int n_used, i;
n_used = evbuffer_peek((struct evbuffer*)input, -1, &ptr, v, 4);
if (n_used < 0)
return -1;
for (i=0;i<n_used;++i) {
evbuffer_add(*output, v[i].iov_base, v[i].iov_len);
tor_assert(v[i].iov_len <= remaining);
remaining -= v[i].iov_len;
evbuffer_ptr_set((struct evbuffer*)input,
&ptr, v[i].iov_len, EVBUFFER_PTR_ADD);
}
}
#else
if (*output)
buf_free(*output);
*output = buf_copy(input);
#endif
return 0;
}
/** Log an error and exit if <b>buf</b> is corrupted.
*/
void
+19
View File
@@ -16,6 +16,7 @@ buf_t *buf_new(void);
buf_t *buf_new_with_capacity(size_t size);
void buf_free(buf_t *buf);
void buf_clear(buf_t *buf);
buf_t *buf_copy(const buf_t *buf);
void buf_shrink(buf_t *buf);
void buf_shrink_freelists(int free_all);
void buf_dump_freelist_sizes(int severity);
@@ -67,6 +68,24 @@ int write_to_evbuffer_zlib(struct evbuffer *buf, tor_zlib_state_t *state,
int done);
#endif
#ifdef USE_BUFFEREVENTS
#define generic_buffer_new() evbuffer_new()
#define generic_buffer_len(b) evbuffer_get_length((b))
#define generic_buffer_add(b,dat,len) evbuffer_add((b),(dat),(len))
#define generic_buffer_get(b,buf,buflen) evbuffer_remove((b),(buf),(buflen))
#define generic_buffer_clear(b) evbuffer_drain((b), evbuffer_get_length((b)))
#define generic_buffer_free(b) evbuffer_free((b))
#else
#define generic_buffer_new() buf_new()
#define generic_buffer_len(b) buf_datalen((b))
#define generic_buffer_add(b,dat,len) write_to_buf((dat),(len),(b))
#define generic_buffer_get(b,buf,buflen) fetch_from_buf((buf),(buflen),(b))
#define generic_buffer_clear(b) buf_clear((b))
#define generic_buffer_free(b) buf_free((b))
#endif
int generic_buffer_set_to_copy(generic_buffer_t **output,
const generic_buffer_t *input);
void assert_buf_ok(buf_t *buf);
#ifdef BUFFERS_PRIVATE
+12 -1
View File
@@ -550,6 +550,16 @@ circuit_free(circuit_t *circ)
crypto_free_pk_env(ocirc->intro_key);
rend_data_free(ocirc->rend_data);
tor_free(ocirc->dest_address);
if (ocirc->socks_username) {
memset(ocirc->socks_username, 0x12, ocirc->socks_username_len);
tor_free(ocirc->socks_username);
}
if (ocirc->socks_password) {
memset(ocirc->socks_password, 0x06, ocirc->socks_password_len);
tor_free(ocirc->socks_password);
}
} else {
or_circuit_t *ocirc = TO_OR_CIRCUIT(circ);
/* Remember cell statistics for this circuit before deallocating. */
@@ -1001,7 +1011,8 @@ circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
(!need_capacity || circ->build_state->need_capacity) &&
(internal == circ->build_state->is_internal) &&
circ->remaining_relay_early_cells &&
!circ->build_state->onehop_tunnel) {
!circ->build_state->onehop_tunnel &&
!circ->isolation_values_set) {
if (info) {
/* need to make sure we don't duplicate hops */
crypt_path_t *hop = circ->cpath;
+170 -22
View File
@@ -18,6 +18,7 @@
#include "connection_edge.h"
#include "control.h"
#include "nodelist.h"
#include "networkstatus.h"
#include "policies.h"
#include "rendclient.h"
#include "rendcommon.h"
@@ -39,19 +40,19 @@ static void circuit_increment_failure_count(void);
* Else return 0.
*/
static int
circuit_is_acceptable(circuit_t *circ, edge_connection_t *conn,
circuit_is_acceptable(const origin_circuit_t *origin_circ,
const edge_connection_t *conn,
int must_be_open, uint8_t purpose,
int need_uptime, int need_internal,
time_t now)
{
const circuit_t *circ = TO_CIRCUIT(origin_circ);
const node_t *exitnode;
cpath_build_state_t *build_state;
tor_assert(circ);
tor_assert(conn);
tor_assert(conn->socks_request);
if (!CIRCUIT_IS_ORIGIN(circ))
return 0; /* this circ doesn't start at us */
if (must_be_open && (circ->state != CIRCUIT_STATE_OPEN || !circ->n_conn))
return 0; /* ignore non-open circs */
if (circ->marked_for_close)
@@ -86,7 +87,7 @@ circuit_is_acceptable(circuit_t *circ, edge_connection_t *conn,
* circuit, it's the magical extra bob hop. so just check the nickname
* of the one we meant to finish at.
*/
build_state = TO_ORIGIN_CIRCUIT(circ)->build_state;
build_state = origin_circ->build_state;
exitnode = build_state_get_exit_node(build_state);
if (need_uptime && !build_state->need_uptime)
@@ -134,25 +135,37 @@ circuit_is_acceptable(circuit_t *circ, edge_connection_t *conn,
return 0;
}
} else { /* not general */
origin_circuit_t *ocirc = TO_ORIGIN_CIRCUIT(circ);
if ((conn->rend_data && !ocirc->rend_data) ||
(!conn->rend_data && ocirc->rend_data) ||
(conn->rend_data && ocirc->rend_data &&
if ((conn->rend_data && !origin_circ->rend_data) ||
(!conn->rend_data && origin_circ->rend_data) ||
(conn->rend_data && origin_circ->rend_data &&
rend_cmp_service_ids(conn->rend_data->onion_address,
ocirc->rend_data->onion_address))) {
origin_circ->rend_data->onion_address))) {
/* this circ is not for this conn */
return 0;
}
}
if (!connection_edge_compatible_with_circuit(conn, origin_circ)) {
/* conn needs to be isolated from other conns that have already used
* origin_circ */
return 0;
}
return 1;
}
/** Return 1 if circuit <b>a</b> is better than circuit <b>b</b> for
* <b>purpose</b>, and return 0 otherwise. Used by circuit_get_best.
* <b>conn</b>, and return 0 otherwise. Used by circuit_get_best.
*/
static int
circuit_is_better(circuit_t *a, circuit_t *b, uint8_t purpose)
circuit_is_better(const origin_circuit_t *oa, const origin_circuit_t *ob,
const edge_connection_t *conn)
{
const circuit_t *a = TO_CIRCUIT(oa);
const circuit_t *b = TO_CIRCUIT(ob);
const uint8_t purpose = conn->_base.purpose;
int a_bits, b_bits;
switch (purpose) {
case CIRCUIT_PURPOSE_C_GENERAL:
/* if it's used but less dirty it's best;
@@ -166,8 +179,7 @@ circuit_is_better(circuit_t *a, circuit_t *b, uint8_t purpose)
if (a->timestamp_dirty ||
timercmp(&a->timestamp_created, &b->timestamp_created, >))
return 1;
if (CIRCUIT_IS_ORIGIN(b) &&
TO_ORIGIN_CIRCUIT(b)->build_state->is_internal)
if (ob->build_state->is_internal)
/* XXX023 what the heck is this internal thing doing here. I
* think we can get rid of it. circuit_is_acceptable() already
* makes sure that is_internal is exactly what we need it to
@@ -186,6 +198,29 @@ circuit_is_better(circuit_t *a, circuit_t *b, uint8_t purpose)
return 1;
break;
}
/* XXXX023 Maybe this check should get a higher priority to avoid
* using up circuits too rapidly. */
a_bits = connection_edge_update_circuit_isolation(conn,
(origin_circuit_t*)oa, 1);
b_bits = connection_edge_update_circuit_isolation(conn,
(origin_circuit_t*)ob, 1);
/* if x_bits < 0, then we have not used x for anything; better not to dirty
* a connection if we can help it. */
if (a_bits < 0) {
return 0;
} else if (b_bits < 0) {
return 1;
}
a_bits &= ~ oa->isolation_flags_mixed;
a_bits &= ~ ob->isolation_flags_mixed;
if (n_bits_set_u8(a_bits) < n_bits_set_u8(b_bits)) {
/* The fewer new restrictions we need to make on a circuit for stream
* isolation, the better. */
return 1;
}
return 0;
}
@@ -206,10 +241,12 @@ circuit_is_better(circuit_t *a, circuit_t *b, uint8_t purpose)
* closest introduce-purposed circuit that you can find.
*/
static origin_circuit_t *
circuit_get_best(edge_connection_t *conn, int must_be_open, uint8_t purpose,
circuit_get_best(const edge_connection_t *conn,
int must_be_open, uint8_t purpose,
int need_uptime, int need_internal)
{
circuit_t *circ, *best=NULL;
circuit_t *circ;
origin_circuit_t *best=NULL;
struct timeval now;
int intro_going_on_but_too_old = 0;
@@ -222,7 +259,11 @@ circuit_get_best(edge_connection_t *conn, int must_be_open, uint8_t purpose,
tor_gettimeofday(&now);
for (circ=global_circuitlist;circ;circ = circ->next) {
if (!circuit_is_acceptable(circ,conn,must_be_open,purpose,
origin_circuit_t *origin_circ;
if (!CIRCUIT_IS_ORIGIN(circ))
continue;
origin_circ = TO_ORIGIN_CIRCUIT(circ);
if (!circuit_is_acceptable(origin_circ,conn,must_be_open,purpose,
need_uptime,need_internal,now.tv_sec))
continue;
@@ -236,8 +277,8 @@ circuit_get_best(edge_connection_t *conn, int must_be_open, uint8_t purpose,
/* now this is an acceptable circ to hand back. but that doesn't
* mean it's the *best* circ to hand back. try to decide.
*/
if (!best || circuit_is_better(circ,best,purpose))
best = circ;
if (!best || circuit_is_better(origin_circ,best,conn))
best = origin_circ;
}
if (!best && intro_going_on_but_too_old)
@@ -245,7 +286,28 @@ circuit_get_best(edge_connection_t *conn, int must_be_open, uint8_t purpose,
"right now, but it has already taken quite a while. Starting "
"one in parallel.");
return best ? TO_ORIGIN_CIRCUIT(best) : NULL;
return best;
}
/** Return the number of not-yet-open general-purpose origin circuits. */
static int
count_pending_general_client_circuits(void)
{
const circuit_t *circ;
int count = 0;
for (circ = global_circuitlist; circ; circ = circ->next) {
if (circ->marked_for_close ||
circ->state == CIRCUIT_STATE_OPEN ||
circ->purpose != CIRCUIT_PURPOSE_C_GENERAL ||
!CIRCUIT_IS_ORIGIN(circ))
continue;
++count;
}
return count;
}
#if 0
@@ -677,6 +739,7 @@ circuit_detach_stream(circuit_t *circ, edge_connection_t *conn)
tor_assert(conn);
conn->cpath_layer = NULL; /* make sure we don't keep a stale pointer */
conn->may_use_optimistic_data = 0;
conn->on_circuit = NULL;
if (CIRCUIT_IS_ORIGIN(circ)) {
@@ -937,6 +1000,7 @@ circuit_testing_failed(origin_circuit_t *circ, int at_last_hop)
void
circuit_has_opened(origin_circuit_t *circ)
{
int can_try_clearing_isolation = 0, tried_clearing_isolation = 0;
control_event_circuit_status(circ, CIRC_EVENT_BUILT, 0);
/* Remember that this circuit has finished building. Now if we start
@@ -944,9 +1008,12 @@ circuit_has_opened(origin_circuit_t *circ)
* to consider its build time. */
circ->has_opened = 1;
again:
switch (TO_CIRCUIT(circ)->purpose) {
case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
rend_client_rendcirc_has_opened(circ);
can_try_clearing_isolation = 1;
connection_ap_attach_pending();
break;
case CIRCUIT_PURPOSE_C_INTRODUCING:
@@ -955,6 +1022,7 @@ circuit_has_opened(origin_circuit_t *circ)
case CIRCUIT_PURPOSE_C_GENERAL:
/* Tell any AP connections that have been waiting for a new
* circuit that one is ready. */
can_try_clearing_isolation = 1;
connection_ap_attach_pending();
break;
case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
@@ -972,6 +1040,24 @@ circuit_has_opened(origin_circuit_t *circ)
* This won't happen in normal operation, but might happen if the
* controller did it. Just let it slide. */
}
if (/* The circuit may have become non-open if it was cannibalized.*/
circ->_base.state == CIRCUIT_STATE_OPEN &&
/* Only if the purpose is clearable, and only if we haven't tried
* to clear isolation yet, do we try. */
can_try_clearing_isolation && !tried_clearing_isolation &&
/* If !isolation_values_set, there is nothing to clear. */
circ->isolation_values_set &&
/* It's not legal to clear a circuit's isolation info if it's ever had
* streams attached */
!circ->isolation_any_streams_attached) {
/* If we have any isolation information set on this circuit, and
* we didn't manage to attach any streams to it, then we can
* and should clear it and try again. */
circuit_clear_isolation(circ);
tried_clearing_isolation = 1;
goto again;
}
}
/** Called whenever a circuit could not be successfully built.
@@ -1307,6 +1393,20 @@ circuit_get_open_circ_or_launch(edge_connection_t *conn,
if (!circ) {
extend_info_t *extend_info=NULL;
uint8_t new_circ_purpose;
const int n_pending = count_pending_general_client_circuits();
if (n_pending >= options->MaxClientCircuitsPending) {
static ratelim_t delay_limit = RATELIM_INIT(10*60);
char *m;
if ((m = rate_limit_log(&delay_limit, approx_time()))) {
log_notice(LD_APP, "We'd like to launch a circuit to handle a "
"connection, but we already have %d general-purpose client "
"circuits pending. Waiting until some finish.",
n_pending);
tor_free(m);
}
return 0;
}
if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
/* need to pick an intro point */
@@ -1417,12 +1517,20 @@ circuit_get_open_circ_or_launch(edge_connection_t *conn,
rend_client_rendcirc_has_opened(circ);
}
}
}
if (!circ)
} /* endif (!circ) */
if (circ) {
/* Mark the circuit with the isolation fields for this connection.
* When the circuit arrives, we'll clear these flags: this is
* just some internal bookkeeping to make sure that we have
* launched enough circuits.
*/
connection_edge_update_circuit_isolation(conn, circ, 0);
} else {
log_info(LD_APP,
"No safe circuit (purpose %d) ready for edge "
"connection; delaying.",
desired_circuit_purpose);
}
*circp = circ;
return 0;
}
@@ -1441,6 +1549,21 @@ cpath_is_on_circuit(origin_circuit_t *circ, crypt_path_t *crypt_path)
return 0;
}
/** Return true iff client-side optimistic data is supported. */
static int
optimistic_data_enabled(void)
{
const or_options_t *options = get_options();
if (options->OptimisticData < 0) {
/* XXX023 consider having auto default to 1 rather than 0 before
* the 0.2.3 branch goes stable. See bug 3617. -RD */
const int32_t enabled =
networkstatus_get_param(NULL, "UseOptimisticData", 0, 0, 1);
return (int)enabled;
}
return options->OptimisticData;
}
/** Attach the AP stream <b>apconn</b> to circ's linked list of
* p_streams. Also set apconn's cpath_layer to <b>cpath</b>, or to the last
* hop in circ's cpath if <b>cpath</b> is NULL.
@@ -1449,6 +1572,8 @@ static void
link_apconn_to_circ(edge_connection_t *apconn, origin_circuit_t *circ,
crypt_path_t *cpath)
{
const node_t *exitnode;
/* add it into the linked list of streams on this circuit */
log_debug(LD_APP|LD_CIRC, "attaching new conn to circ. n_circ_id %d.",
circ->_base.n_circ_id);
@@ -1468,6 +1593,28 @@ link_apconn_to_circ(edge_connection_t *apconn, origin_circuit_t *circ,
tor_assert(circ->cpath->prev->state == CPATH_STATE_OPEN);
apconn->cpath_layer = circ->cpath->prev;
}
circ->isolation_any_streams_attached = 1;
connection_edge_update_circuit_isolation(apconn, circ, 0);
/* See if we can use optimistic data on this circuit */
if (apconn->cpath_layer->extend_info &&
(exitnode = node_get_by_id(
apconn->cpath_layer->extend_info->identity_digest)) &&
exitnode->rs) {
/* Okay; we know what exit node this is. */
if (optimistic_data_enabled() &&
circ->_base.purpose == CIRCUIT_PURPOSE_C_GENERAL &&
exitnode->rs->version_supports_optimistic_data)
apconn->may_use_optimistic_data = 1;
else
apconn->may_use_optimistic_data = 0;
log_info(LD_APP, "Looks like completed circuit to %s %s allow "
"optimistic data for connection to %s",
safe_str_client(node_describe(exitnode)),
apconn->may_use_optimistic_data ? "does" : "doesn't",
safe_str_client(apconn->socks_request->address));
}
}
/** Return true iff <b>address</b> is matched by one of the entries in
@@ -1495,7 +1642,8 @@ hostname_in_track_host_exits(const or_options_t *options, const char *address)
* <b>conn</b>'s destination.
*/
static void
consider_recording_trackhost(edge_connection_t *conn, origin_circuit_t *circ)
consider_recording_trackhost(const edge_connection_t *conn,
const origin_circuit_t *circ)
{
const or_options_t *options = get_options();
char *new_address = NULL;
+438 -66
View File
@@ -40,6 +40,9 @@
#include "procmon.h"
/* From main.c */
extern int quiet_level;
/** Enumeration of types which option values can take */
typedef enum config_type_t {
CONFIG_TYPE_STRING = 0, /**< An arbitrary string. */
@@ -240,7 +243,7 @@ static config_var_t _option_vars[] = {
VAR("DirServer", LINELIST, DirServers, NULL),
V(DisableAllSwap, BOOL, "0"),
V(DisableIOCP, BOOL, "1"),
V(DNSPort, PORT, "0"),
V(DNSPort, LINELIST, NULL),
V(DNSListenAddress, LINELIST, NULL),
V(DownloadExtraInfo, BOOL, "0"),
V(EnforceDistinctSubnets, BOOL, "1"),
@@ -315,13 +318,14 @@ static config_var_t _option_vars[] = {
VAR("MapAddress", LINELIST, AddressMap, NULL),
V(MaxAdvertisedBandwidth, MEMUNIT, "1 GB"),
V(MaxCircuitDirtiness, INTERVAL, "10 minutes"),
V(MaxClientCircuitsPending, UINT, "32"),
V(MaxOnionsPending, UINT, "100"),
OBSOLETE("MonthlyAccountingStart"),
V(MyFamily, STRING, NULL),
V(NewCircuitPeriod, INTERVAL, "30 seconds"),
VAR("NamingAuthoritativeDirectory",BOOL, NamingAuthoritativeDir, "0"),
V(NATDListenAddress, LINELIST, NULL),
V(NATDPort, PORT, "0"),
V(NATDPort, LINELIST, NULL),
V(Nickname, STRING, NULL),
V(WarnUnsafeSocks, BOOL, "1"),
OBSOLETE("NoPublish"),
@@ -336,6 +340,7 @@ static config_var_t _option_vars[] = {
V(PerConnBWRate, MEMUNIT, "0"),
V(PidFile, STRING, NULL),
V(TestingTorNetwork, BOOL, "0"),
V(OptimisticData, AUTOBOOL, "auto"),
V(PortForwarding, BOOL, "0"),
V(PortForwardingHelper, FILENAME, "tor-fw-helper"),
V(PreferTunneledDirConns, BOOL, "1"),
@@ -374,7 +379,7 @@ static config_var_t _option_vars[] = {
V(ShutdownWaitLength, INTERVAL, "30 seconds"),
V(SocksListenAddress, LINELIST, NULL),
V(SocksPolicy, LINELIST, NULL),
V(SocksPort, PORT, "9050"),
V(SocksPort, LINELIST, NULL),
V(SocksTimeout, INTERVAL, "2 minutes"),
OBSOLETE("StatusFetchPeriod"),
V(StrictNodes, BOOL, "0"),
@@ -385,7 +390,7 @@ static config_var_t _option_vars[] = {
V(TrackHostExitsExpire, INTERVAL, "30 minutes"),
OBSOLETE("TrafficShaping"),
V(TransListenAddress, LINELIST, NULL),
V(TransPort, PORT, "0"),
V(TransPort, LINELIST, NULL),
V(TunnelDirConns, BOOL, "1"),
V(UpdateBridgesFromAuthority, BOOL, "0"),
V(UseBridges, BOOL, "0"),
@@ -577,6 +582,9 @@ static int parse_client_transport_line(const char *line, int validate_only);
static int parse_dir_server_line(const char *line,
dirinfo_type_t required_type,
int validate_only);
static void port_cfg_free(port_cfg_t *port);
static int parse_client_ports(const or_options_t *options, int validate_only,
char **msg_out, int *n_ports_out);
static int validate_data_directory(or_options_t *options);
static int write_configuration_file(const char *fname,
const or_options_t *options);
@@ -646,6 +654,8 @@ static or_state_t *global_state = NULL;
static config_line_t *global_cmdline_options = NULL;
/** Contents of most recently read DirPortFrontPage file. */
static char *global_dirfrontpagecontents = NULL;
/** List of port_cfg_t for client-level (SOCKS, DNS, Trans, NATD) ports. */
static smartlist_t *configured_client_ports = NULL;
/** Return the contents of our frontpage string, or NULL if not configured. */
const char *
@@ -686,6 +696,9 @@ get_options(void)
int
set_options(or_options_t *new_val, char **msg)
{
int i;
smartlist_t *elements;
config_line_t *line;
or_options_t *old_options = global_options;
global_options = new_val;
/* Note that we pass the *old* options below, for comparison. It
@@ -700,7 +713,34 @@ set_options(or_options_t *new_val, char **msg)
"Acting on config options left us in a broken state. Dying.");
exit(1);
}
/* Issues a CONF_CHANGED event to notify controller of the change. If Tor is
* just starting up then the old_options will be undefined. */
if (old_options) {
elements = smartlist_create();
for (i=0; options_format.vars[i].name; ++i) {
const config_var_t *var = &options_format.vars[i];
const char *var_name = var->name;
if (var->type == CONFIG_TYPE_LINELIST_S ||
var->type == CONFIG_TYPE_OBSOLETE) {
continue;
}
if (!option_is_same(&options_format, new_val, old_options, var_name)) {
line = get_assigned_option(&options_format, new_val, var_name, 1);
if (line) {
for (; line; line = line->next) {
smartlist_add(elements, line->key);
smartlist_add(elements, line->value);
}
} else {
smartlist_add(elements, (char*)options_format.vars[i].name);
smartlist_add(elements, NULL);
}
}
}
control_event_conf_changed(elements);
smartlist_free(elements);
}
config_free(&options_format, old_options);
return 0;
@@ -758,6 +798,13 @@ config_free_all(void)
config_free_lines(global_cmdline_options);
global_cmdline_options = NULL;
if (configured_client_ports) {
SMARTLIST_FOREACH(configured_client_ports,
port_cfg_t *, p, tor_free(p));
smartlist_free(configured_client_ports);
configured_client_ports = NULL;
}
tor_free(torrc_fname);
tor_free(_version);
tor_free(global_dirfrontpagecontents);
@@ -1004,6 +1051,7 @@ options_act_reversible(const or_options_t *old_options, char **msg)
#endif
if (running_tor) {
int n_client_ports=0;
/* We need to set the connection limit before we can open the listeners. */
if (set_max_file_descriptors((unsigned)options->ConnLimit,
&options->_ConnLimit) < 0) {
@@ -1019,6 +1067,10 @@ options_act_reversible(const or_options_t *old_options, char **msg)
libevent_initialized = 1;
}
/* Adjust the client port configuration so we can launch listeners. */
if (parse_client_ports(options, 0, msg, &n_client_ports))
return -1;
/* Launch the listeners. (We do this before we setuid, so we can bind to
* ports under 1024.) We don't want to rebind if we're hibernating. */
if (!we_are_hibernating()) {
@@ -1068,6 +1120,9 @@ options_act_reversible(const or_options_t *old_options, char **msg)
/* No need to roll back, since you can't change the value. */
}
/* Write control ports to disk as appropriate */
control_ports_write_to_file();
if (directory_caches_v2_dir_info(options)) {
size_t len = strlen(options->DataDirectory)+32;
char *fn = tor_malloc(len);
@@ -3027,6 +3082,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
int i;
config_line_t *cl;
const char *uname = get_uname();
int n_client_ports=0;
#define REJECT(arg) \
STMT_BEGIN *msg = tor_strdup(arg); return -1; STMT_END
#define COMPLAIN(arg) STMT_BEGIN log(LOG_WARN, LD_CONFIG, arg); STMT_END
@@ -3050,57 +3106,8 @@ options_validate(or_options_t *old_options, or_options_t *options,
if (options->DirPort == 0 && options->DirListenAddress != NULL)
REJECT("DirPort must be defined if DirListenAddress is defined.");
if (options->DNSPort == 0 && options->DNSListenAddress != NULL)
REJECT("DNSPort must be defined if DNSListenAddress is defined.");
if (options->ControlPort == 0 && options->ControlListenAddress != NULL)
REJECT("ControlPort must be defined if ControlListenAddress is defined.");
if (options->TransPort == 0 && options->TransListenAddress != NULL)
REJECT("TransPort must be defined if TransListenAddress is defined.");
if (options->NATDPort == 0 && options->NATDListenAddress != NULL)
REJECT("NATDPort must be defined if NATDListenAddress is defined.");
/* Don't gripe about SocksPort 0 with SocksListenAddress set; a standard
* configuration does this. */
for (i = 0; i < 3; ++i) {
int is_socks = i==0;
int is_trans = i==1;
config_line_t *line, *opt, *old;
const char *tp;
if (is_socks) {
opt = options->SocksListenAddress;
old = old_options ? old_options->SocksListenAddress : NULL;
tp = "SOCKS proxy";
} else if (is_trans) {
opt = options->TransListenAddress;
old = old_options ? old_options->TransListenAddress : NULL;
tp = "transparent proxy";
} else {
opt = options->NATDListenAddress;
old = old_options ? old_options->NATDListenAddress : NULL;
tp = "natd proxy";
}
for (line = opt; line; line = line->next) {
char *address = NULL;
uint16_t port;
uint32_t addr;
if (parse_addr_port(LOG_WARN, line->value, &address, &addr, &port)<0)
continue; /* We'll warn about this later. */
if (!is_internal_IP(addr, 1) &&
(!old_options || !config_lines_eq(old, opt))) {
log_warn(LD_CONFIG,
"You specified a public address '%s' for a %s. Other "
"people on the Internet might find your computer and use it as "
"an open %s. Please don't allow this unless you have "
"a good reason.", address, tp, tp);
}
tor_free(address);
}
}
if (parse_client_ports(options, 1, msg, &n_client_ports) < 0)
return -1;
if (validate_data_directory(options)<0)
REJECT("Invalid DataDirectory");
@@ -3124,8 +3131,12 @@ options_validate(or_options_t *old_options, or_options_t *options,
"misconfigured or something else goes wrong.");
/* Special case on first boot if no Log options are given. */
if (!options->Logs && !options->RunAsDaemon && !from_setconf)
config_line_append(&options->Logs, "Log", "notice stdout");
if (!options->Logs && !options->RunAsDaemon && !from_setconf) {
if (quiet_level == 0)
config_line_append(&options->Logs, "Log", "notice stdout");
else if (quiet_level == 1)
config_line_append(&options->Logs, "Log", "warn stdout");
}
if (options_init_logs(options, 1)<0) /* Validate the log(s) */
REJECT("Failed to validate Log options. See logs for details.");
@@ -3142,9 +3153,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
REJECT("Can't use a relative path to torrc when RunAsDaemon is set.");
#endif
if (options->SocksPort == 0 && options->TransPort == 0 &&
options->NATDPort == 0 && options->ORPort == 0 &&
options->DNSPort == 0 && !options->RendConfigLines)
if (n_client_ports == 0 && options->ORPort == 0 && !options->RendConfigLines)
log(LOG_WARN, LD_CONFIG,
"SocksPort, TransPort, NATDPort, DNSPort, and ORPort are all "
"undefined, and there aren't any hidden services configured. "
@@ -3253,6 +3262,15 @@ options_validate(or_options_t *old_options, or_options_t *options,
return -1;
}
if (options->MaxClientCircuitsPending <= 0 ||
options->MaxClientCircuitsPending > MAX_MAX_CLIENT_CIRCUITS_PENDING) {
tor_asprintf(msg,
"MaxClientCircuitsPending must be between 1 and %d, but "
"was set to %d", MAX_MAX_CLIENT_CIRCUITS_PENDING,
options->MaxClientCircuitsPending);
return -1;
}
if (validate_ports_csv(options->FirewallPorts, "FirewallPorts", msg) < 0)
return -1;
@@ -3892,12 +3910,7 @@ options_validate(or_options_t *old_options, or_options_t *options,
static int
opt_streq(const char *s1, const char *s2)
{
if (!s1 && !s2)
return 1;
else if (s1 && s2 && !strcmp(s1,s2))
return 1;
else
return 0;
return 0 == strcmp_opt(s1, s2);
}
/** Check if any of the previous options have changed but aren't allowed to. */
@@ -4885,6 +4898,365 @@ parse_dir_server_line(const char *line, dirinfo_type_t required_type,
return r;
}
/** Free all storage held in <b>port</b> */
static void
port_cfg_free(port_cfg_t *port)
{
tor_free(port);
}
/** Warn for every port in <b>ports</b> that is not on a loopback address. */
static void
warn_nonlocal_client_ports(const smartlist_t *ports, const char *portname)
{
SMARTLIST_FOREACH_BEGIN(ports, const port_cfg_t *, port) {
if (!tor_addr_is_loopback(&port->addr)) {
log_warn(LD_CONFIG, "You specified a public address for %sPort. "
"Other people on the Internet might find your computer and "
"use it as an open proxy. Please don't allow this unless you "
"have a good reason.", portname);
}
} SMARTLIST_FOREACH_END(port);
}
#define CL_PORT_NO_OPTIONS (1u<<0)
#define CL_PORT_WARN_NONLOCAL (1u<<1)
#define CL_PORT_ALLOW_EXTRA_LISTENADDR (1u<<2)
/**
* Parse port configuration for a single client port type.
*
* Read entries of the "FooPort" type from the list <b>ports</b>, and
* entries of the "FooListenAddress" type from the list
* <b>listenaddrs</b>. Two syntaxes are supported: a legacy syntax
* where FooPort is at most a single entry containing a port number and
* where FooListenAddress has any number of address:port combinations;
* and a new syntax where there are no FooListenAddress entries and
* where FooPort can have any number of entries of the format
* "[Address:][Port] IsolationOptions".
*
* In log messages, describe the port type as <b>portname</b>.
*
* If no address is specified, default to <b>defaultaddr</b>. If no
* FooPort is given, default to defaultport (if 0, there is no default).
*
* If CL_PORT_NO_OPTIONS is set in <b>flags</b>, do not allow stream
* isolation options in the FooPort entries.
*
* If CL_PORT_WARN_NONLOCAL is set in <b>flags</b>, warn if any of the
* ports are not on a local address.
*
* Unless CL_PORT_ALLOW_EXTRA_LISTENADDR is set in <b>flags</b>, warn
* if FooListenAddress is set but FooPort is 0.
*
* On success, if <b>out</b> is given, add a new port_cfg_t entry to
* <b>out</b> for every port that the client should listen on. Return 0
* on success, -1 on failure.
*/
static int
parse_client_port_config(smartlist_t *out,
const config_line_t *ports,
const config_line_t *listenaddrs,
const char *portname,
int listener_type,
const char *defaultaddr,
int defaultport,
unsigned flags)
{
smartlist_t *elts;
int retval = -1;
const unsigned allow_client_options = !(flags & CL_PORT_NO_OPTIONS);
const unsigned warn_nonlocal = flags & CL_PORT_WARN_NONLOCAL;
const unsigned allow_spurious_listenaddr =
flags & CL_PORT_ALLOW_EXTRA_LISTENADDR;
/* FooListenAddress is deprecated; let's make it work like it used to work,
* though. */
if (listenaddrs) {
int mainport = defaultport;
if (ports && ports->next) {
log_warn(LD_CONFIG, "%sListenAddress can't be used when there are "
"multiple %sPort lines", portname, portname);
return -1;
} else if (ports) {
if (!strcmp(ports->value, "auto")) {
mainport = CFG_AUTO_PORT;
} else {
int ok;
mainport = (int)tor_parse_long(ports->value, 10, 0, 65535, &ok, NULL);
if (!ok) {
log_warn(LD_CONFIG, "%sListenAddress can only be used with a single "
"%sPort with value \"auto\" or 1-65535.", portname, portname);
return -1;
}
}
}
if (mainport == 0) {
if (allow_spurious_listenaddr)
return 1;
log_warn(LD_CONFIG, "%sPort must be defined if %sListenAddress is used",
portname, portname);
return -1;
}
for (; listenaddrs; listenaddrs = listenaddrs->next) {
tor_addr_t addr;
uint16_t port = 0;
if (tor_addr_port_parse(listenaddrs->value, &addr, &port) < 0) {
log_warn(LD_CONFIG, "Unable to parse %sListenAddress '%s'",
portname, listenaddrs->value);
return -1;
}
if (out) {
port_cfg_t *cfg = tor_malloc_zero(sizeof(port_cfg_t));
cfg->type = listener_type;
cfg->port = port ? port : defaultport;
tor_addr_copy(&cfg->addr, &addr);
cfg->session_group = SESSION_GROUP_UNSET;
cfg->isolation_flags = ISO_DEFAULT;
smartlist_add(out, cfg);
}
}
if (warn_nonlocal && out)
warn_nonlocal_client_ports(out, portname);
return 0;
} /* end if (listenaddrs) */
/* No ListenAddress lines. If there's no FooPort, then maybe make a default
* one. */
if (! ports) {
if (defaultport && out) {
port_cfg_t *cfg = tor_malloc_zero(sizeof(port_cfg_t));
cfg->type = listener_type;
cfg->port = defaultport;
tor_addr_from_str(&cfg->addr, defaultaddr);
cfg->session_group = SESSION_GROUP_UNSET;
cfg->isolation_flags = ISO_DEFAULT;
smartlist_add(out, cfg);
}
return 0;
}
/* At last we can actually parse the FooPort lines. The syntax is:
* [Addr:](Port|auto) [Options].*/
elts = smartlist_create();
for (; ports; ports = ports->next) {
tor_addr_t addr;
int port;
int sessiongroup = SESSION_GROUP_UNSET;
unsigned isolation = ISO_DEFAULT;
char *addrport;
uint16_t ptmp=0;
int ok;
smartlist_split_string(elts, ports->value, NULL,
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
if (smartlist_len(elts) == 0) {
log_warn(LD_CONFIG, "Invalid %sPort line with no value", portname);
goto err;
}
if (!allow_client_options && smartlist_len(elts) > 1) {
log_warn(LD_CONFIG, "Too many options on %sPort line", portname);
goto err;
}
/* Now parse the addr/port value */
addrport = smartlist_get(elts, 0);
if (!strcmp(addrport, "auto")) {
port = CFG_AUTO_PORT;
tor_addr_from_str(&addr, defaultaddr);
} else if (!strcasecmpend(addrport, ":auto")) {
char *addrtmp = tor_strndup(addrport, strlen(addrport)-5);
port = CFG_AUTO_PORT;
if (tor_addr_port_parse(addrtmp, &addr, &ptmp)<0 || ptmp) {
log_warn(LD_CONFIG, "Invalid address '%s' for %sPort",
escaped(addrport), portname);
tor_free(addrtmp);
goto err;
}
} else {
/* Try parsing integer port before address, because, who knows?
"9050" might be a valid address. */
port = (int) tor_parse_long(addrport, 10, 0, 65535, &ok, NULL);
if (ok) {
tor_addr_from_str(&addr, defaultaddr);
} else if (tor_addr_port_parse(addrport, &addr, &ptmp) == 0) {
if (ptmp == 0) {
log_warn(LD_CONFIG, "%sPort line has address but no port", portname);
goto err;
}
port = ptmp;
} else {
log_warn(LD_CONFIG, "Couldn't parse address '%s' for %sPort",
escaped(addrport), portname);
goto err;
}
}
/* Now parse the rest of the options, if any. */
SMARTLIST_FOREACH_BEGIN(elts, char *, elt) {
int no = 0, isoflag = 0;
const char *elt_orig = elt;
if (elt_sl_idx == 0)
continue; /* Skip addr:port */
if (!strcasecmpstart(elt, "SessionGroup=")) {
int group = (int)tor_parse_long(elt+strlen("SessionGroup="),
10, 0, INT_MAX, &ok, NULL);
if (!ok) {
log_warn(LD_CONFIG, "Invalid %sPort option '%s'",
portname, escaped(elt));
goto err;
}
if (sessiongroup >= 0) {
log_warn(LD_CONFIG, "Multiple SessionGroup options on %sPort",
portname);
goto err;
}
sessiongroup = group;
continue;
}
if (!strcasecmpstart(elt, "No")) {
no = 1;
elt += 2;
}
if (!strcasecmpend(elt, "s"))
elt[strlen(elt)-1] = '\0'; /* kill plurals. */
if (!strcasecmp(elt, "IsolateDestPort")) {
isoflag = ISO_DESTPORT;
} else if (!strcasecmp(elt, "IsolateDestAddr")) {
isoflag = ISO_DESTADDR;
} else if (!strcasecmp(elt, "IsolateSOCKSAuth")) {
isoflag = ISO_SOCKSAUTH;
} else if (!strcasecmp(elt, "IsolateClientProtocol")) {
isoflag = ISO_CLIENTPROTO;
} else if (!strcasecmp(elt, "IsolateClientAddr")) {
isoflag = ISO_CLIENTADDR;
} else {
log_warn(LD_CONFIG, "Unrecognized %sPort option '%s'",
portname, escaped(elt_orig));
}
if (no) {
isolation &= ~isoflag;
} else {
isolation |= isoflag;
}
} SMARTLIST_FOREACH_END(elt);
if (out && port) {
port_cfg_t *cfg = tor_malloc_zero(sizeof(port_cfg_t));
cfg->type = listener_type;
cfg->port = port;
tor_addr_copy(&cfg->addr, &addr);
cfg->session_group = sessiongroup;
cfg->isolation_flags = isolation;
smartlist_add(out, cfg);
}
SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp));
smartlist_clear(elts);
}
if (warn_nonlocal && out)
warn_nonlocal_client_ports(out, portname);
retval = 0;
err:
SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp));
smartlist_free(elts);
return retval;
}
/** Parse all client port types (Socks, DNS, Trans, NATD) from
* <b>options</b>. On success, set *<b>n_ports_out</b> to the number of
* ports that are listed and return 0. On failure, set *<b>msg</b> to a
* description of the problem and return -1.
*
* If <b>validate_only</b> is false, set configured_client_ports to the
* new list of ports parsed from <b>options</b>.
**/
static int
parse_client_ports(const or_options_t *options, int validate_only,
char **msg, int *n_ports_out)
{
smartlist_t *ports;
int retval = -1;
ports = smartlist_create();
*n_ports_out = 0;
if (parse_client_port_config(ports,
options->SocksPort, options->SocksListenAddress,
"Socks", CONN_TYPE_AP_LISTENER,
"127.0.0.1", 9050,
CL_PORT_WARN_NONLOCAL|CL_PORT_ALLOW_EXTRA_LISTENADDR) < 0) {
*msg = tor_strdup("Invalid SocksPort/SocksListenAddress configuration");
goto err;
}
if (parse_client_port_config(ports,
options->DNSPort, options->DNSListenAddress,
"DNS", CONN_TYPE_AP_DNS_LISTENER,
"127.0.0.1", 0,
CL_PORT_WARN_NONLOCAL) < 0) {
*msg = tor_strdup("Invalid DNSPort/DNSListenAddress configuration");
goto err;
}
if (parse_client_port_config(ports,
options->TransPort, options->TransListenAddress,
"Trans", CONN_TYPE_AP_TRANS_LISTENER,
"127.0.0.1", 0,
CL_PORT_WARN_NONLOCAL) < 0) {
*msg = tor_strdup("Invalid TransPort/TransListenAddress configuration");
goto err;
}
if (parse_client_port_config(ports,
options->NATDPort, options->NATDListenAddress,
"NATD", CONN_TYPE_AP_NATD_LISTENER,
"127.0.0.1", 0,
CL_PORT_WARN_NONLOCAL) < 0) {
*msg = tor_strdup("Invalid NatdPort/NatdListenAddress configuration");
goto err;
}
*n_ports_out = smartlist_len(ports);
if (!validate_only) {
if (configured_client_ports) {
SMARTLIST_FOREACH(configured_client_ports,
port_cfg_t *, p, port_cfg_free(p));
smartlist_free(configured_client_ports);
}
configured_client_ports = ports;
ports = NULL; /* prevent free below. */
}
retval = 0;
err:
if (ports) {
SMARTLIST_FOREACH(ports, port_cfg_t *, p, port_cfg_free(p));
smartlist_free(ports);
}
return retval;
}
/** Return a list of port_cfg_t for client ports parsed from the
* options. */
const smartlist_t *
get_configured_client_ports(void)
{
if (!configured_client_ports)
configured_client_ports = smartlist_create();
return configured_client_ports;
}
/** Adjust the value of options->DataDirectory, or fill it in if it's
* absent. Return 0 on success, -1 on failure. */
static int
+2
View File
@@ -64,6 +64,8 @@ or_state_t *get_or_state(void);
int did_last_state_file_write_fail(void);
int or_state_save(time_t now);
const smartlist_t *get_configured_client_ports(void);
int options_need_geoip_info(const or_options_t *options,
const char **reason_out);
int getinfo_helper_config(control_connection_t *conn,
+315 -285
View File
@@ -43,11 +43,12 @@
static connection_t *connection_create_listener(
const struct sockaddr *listensockaddr,
socklen_t listensocklen, int type,
char* address);
const char *address,
const port_cfg_t *portcfg);
static void connection_init(time_t now, connection_t *conn, int type,
int socket_family);
static int connection_init_accepted_conn(connection_t *conn,
uint8_t listener_type);
const listener_connection_t *listener);
static int connection_handle_listener_read(connection_t *conn, int new_type);
#ifndef USE_BUFFEREVENTS
static int connection_bucket_should_increase(int bucket,
@@ -76,6 +77,15 @@ static uint32_t last_interface_ip = 0;
* Used to detect IP address changes. */
static smartlist_t *outgoing_addrs = NULL;
#define CASE_ANY_LISTENER_TYPE \
case CONN_TYPE_OR_LISTENER: \
case CONN_TYPE_AP_LISTENER: \
case CONN_TYPE_DIR_LISTENER: \
case CONN_TYPE_CONTROL_LISTENER: \
case CONN_TYPE_AP_TRANS_LISTENER: \
case CONN_TYPE_AP_NATD_LISTENER: \
case CONN_TYPE_AP_DNS_LISTENER
/**************************************************************/
/**
@@ -116,13 +126,7 @@ conn_state_to_string(int type, int state)
{
static char buf[96];
switch (type) {
case CONN_TYPE_OR_LISTENER:
case CONN_TYPE_AP_LISTENER:
case CONN_TYPE_AP_TRANS_LISTENER:
case CONN_TYPE_AP_NATD_LISTENER:
case CONN_TYPE_AP_DNS_LISTENER:
case CONN_TYPE_DIR_LISTENER:
case CONN_TYPE_CONTROL_LISTENER:
CASE_ANY_LISTENER_TYPE:
if (state == LISTENER_STATE_READY)
return "ready";
break;
@@ -265,6 +269,17 @@ control_connection_new(int socket_family)
return control_conn;
}
/** Allocate and return a new listener_connection_t, initialized as by
* connection_init(). */
listener_connection_t *
listener_connection_new(int type, int socket_family)
{
listener_connection_t *listener_conn =
tor_malloc_zero(sizeof(listener_connection_t));
connection_init(time(NULL), TO_CONN(listener_conn), type, socket_family);
return listener_conn;
}
/** Allocate, initialize, and return a new connection_t subtype of <b>type</b>
* to make or receive connections of address family <b>socket_family</b>. The
* type should be one of the CONN_TYPE_* constants. */
@@ -285,6 +300,9 @@ connection_new(int type, int socket_family)
case CONN_TYPE_CONTROL:
return TO_CONN(control_connection_new(socket_family));
CASE_ANY_LISTENER_TYPE:
return TO_CONN(listener_connection_new(type, socket_family));
default: {
connection_t *conn = tor_malloc_zero(sizeof(connection_t));
connection_init(time(NULL), conn, type, socket_family);
@@ -325,6 +343,9 @@ connection_init(time_t now, connection_t *conn, int type, int socket_family)
case CONN_TYPE_CONTROL:
conn->magic = CONTROL_CONNECTION_MAGIC;
break;
CASE_ANY_LISTENER_TYPE:
conn->magic = LISTENER_CONNECTION_MAGIC;
break;
default:
conn->magic = BASE_CONNECTION_MAGIC;
break;
@@ -396,6 +417,11 @@ _connection_free(connection_t *conn)
mem = TO_CONTROL_CONN(conn);
memlen = sizeof(control_connection_t);
break;
CASE_ANY_LISTENER_TYPE:
tor_assert(conn->magic == LISTENER_CONNECTION_MAGIC);
mem = TO_LISTENER_CONN(conn);
memlen = sizeof(listener_connection_t);
break;
default:
tor_assert(conn->magic == BASE_CONNECTION_MAGIC);
mem = conn;
@@ -442,9 +468,15 @@ _connection_free(connection_t *conn)
if (CONN_IS_EDGE(conn)) {
edge_connection_t *edge_conn = TO_EDGE_CONN(conn);
tor_free(edge_conn->chosen_exit_name);
tor_free(edge_conn->original_dest_address);
if (edge_conn->socks_request)
socks_request_free(edge_conn->socks_request);
if (edge_conn->pending_optimistic_data) {
generic_buffer_free(edge_conn->pending_optimistic_data);
}
if (edge_conn->sending_optimistic_data) {
generic_buffer_free(edge_conn->sending_optimistic_data);
}
rend_data_free(edge_conn->rend_data);
}
if (conn->type == CONN_TYPE_CONTROL) {
@@ -529,41 +561,6 @@ connection_free(connection_t *conn)
_connection_free(conn);
}
/** Call _connection_free() on every connection in our array, and release all
* storage held by connection.c. This is used by cpuworkers and dnsworkers
* when they fork, so they don't keep resources held open (especially
* sockets).
*
* Don't do the checks in connection_free(), because they will
* fail.
*/
void
connection_free_all(void)
{
smartlist_t *conns = get_connection_array();
/* We don't want to log any messages to controllers. */
SMARTLIST_FOREACH(conns, connection_t *, conn,
if (conn->type == CONN_TYPE_CONTROL)
TO_CONTROL_CONN(conn)->event_mask = 0);
control_update_global_event_mask();
/* Unlink everything from the identity map. */
connection_or_clear_identity_map();
/* Clear out our list of broken connections */
clear_broken_connection_map(0);
SMARTLIST_FOREACH(conns, connection_t *, conn, _connection_free(conn));
if (outgoing_addrs) {
SMARTLIST_FOREACH(outgoing_addrs, void*, addr, tor_free(addr));
smartlist_free(outgoing_addrs);
outgoing_addrs = NULL;
}
}
/**
* Called when we're about to finally unlink and free a connection:
* perform necessary accounting and cleanup
@@ -701,48 +698,6 @@ connection_expire_held_open(void)
});
}
/** Create an AF_INET listenaddr struct.
* <b>listenaddress</b> provides the host and optionally the port information
* for the new structure. If no port is provided in <b>listenaddress</b> then
* <b>listenport</b> is used.
*
* If not NULL <b>readable_address</b> will contain a copy of the host part of
* <b>listenaddress</b>.
*
* The listenaddr struct has to be freed by the caller.
*/
static struct sockaddr_in *
create_inet_sockaddr(const char *listenaddress, int listenport,
char **readable_address, socklen_t *socklen_out) {
struct sockaddr_in *listenaddr = NULL;
uint32_t addr;
uint16_t usePort = 0;
if (parse_addr_port(LOG_WARN,
listenaddress, readable_address, &addr, &usePort)<0) {
log_warn(LD_CONFIG,
"Error parsing/resolving ListenAddress %s", listenaddress);
goto err;
}
if (usePort==0) {
if (listenport != CFG_AUTO_PORT)
usePort = listenport;
}
listenaddr = tor_malloc_zero(sizeof(struct sockaddr_in));
listenaddr->sin_addr.s_addr = htonl(addr);
listenaddr->sin_family = AF_INET;
listenaddr->sin_port = htons((uint16_t) usePort);
*socklen_out = sizeof(struct sockaddr_in);
return listenaddr;
err:
tor_free(listenaddr);
return NULL;
}
#ifdef HAVE_SYS_UN_H
/** Create an AF_UNIX listenaddr struct.
* <b>listenaddress</b> provides the path to the Unix socket.
@@ -877,12 +832,16 @@ make_socket_reuseable(tor_socket_t sock)
static connection_t *
connection_create_listener(const struct sockaddr *listensockaddr,
socklen_t socklen,
int type, char* address)
int type, const char *address,
const port_cfg_t *port_cfg)
{
listener_connection_t *lis_conn;
connection_t *conn;
tor_socket_t s; /* the socket we're going to make */
uint16_t usePort = 0, gotPort = 0;
int start_reading = 0;
static int global_next_session_group = SESSION_GROUP_FIRST_AUTO;
tor_addr_t addr;
if (get_n_open_sockets() >= get_options()->_ConnLimit-1) {
warn_too_many_conns();
@@ -890,7 +849,6 @@ connection_create_listener(const struct sockaddr *listensockaddr,
}
if (listensockaddr->sa_family == AF_INET) {
tor_addr_t addr;
int is_tcp = (type != CONN_TYPE_AP_DNS_LISTENER);
if (is_tcp)
start_reading = 1;
@@ -958,6 +916,8 @@ connection_create_listener(const struct sockaddr *listensockaddr,
log_notice(LD_NET, "Opening %s on %s",
conn_type_to_string(type), address);
tor_addr_make_unspec(&addr);
if (unlink(address) < 0 && errno != ENOENT) {
log_warn(LD_NET, "Could not unlink %s: %s", address,
strerror(errno));
@@ -999,11 +959,23 @@ connection_create_listener(const struct sockaddr *listensockaddr,
set_socket_nonblocking(s);
conn = connection_new(type, listensockaddr->sa_family);
lis_conn = listener_connection_new(type, listensockaddr->sa_family);
conn = TO_CONN(lis_conn);
conn->socket_family = listensockaddr->sa_family;
conn->s = s;
conn->address = tor_strdup(address);
conn->port = gotPort;
tor_addr_copy(&conn->addr, &addr);
if (port_cfg->isolation_flags) {
lis_conn->isolation_flags = port_cfg->isolation_flags;
if (port_cfg->session_group >= 0) {
lis_conn->session_group = port_cfg->session_group;
} else {
/* XXXX023 This can wrap after ~INT_MAX ports are opened. */
lis_conn->session_group = global_next_session_group--;
}
}
if (connection_add(conn) < 0) { /* no space, forget it */
log_warn(LD_NET,"connection_add for listener failed. Giving up.");
@@ -1015,9 +987,6 @@ connection_create_listener(const struct sockaddr *listensockaddr,
"%s listening on port %u.",
conn_type_to_string(type), gotPort);
if (type == CONN_TYPE_CONTROL_LISTENER)
control_ports_write_to_file();
conn->state = LISTENER_STATE_READY;
if (start_reading) {
connection_start_reading(conn);
@@ -1217,7 +1186,7 @@ connection_handle_listener_read(connection_t *conn, int new_type)
return 0; /* no need to tear down the parent */
}
if (connection_init_accepted_conn(newconn, conn->type) < 0) {
if (connection_init_accepted_conn(newconn, TO_LISTENER_CONN(conn)) < 0) {
if (! newconn->marked_for_close)
connection_mark_for_close(newconn);
return 0;
@@ -1231,7 +1200,8 @@ connection_handle_listener_read(connection_t *conn, int new_type)
* and place it in circuit_wait.
*/
static int
connection_init_accepted_conn(connection_t *conn, uint8_t listener_type)
connection_init_accepted_conn(connection_t *conn,
const listener_connection_t *listener)
{
connection_start_reading(conn);
@@ -1240,7 +1210,11 @@ connection_init_accepted_conn(connection_t *conn, uint8_t listener_type)
control_event_or_conn_status(TO_OR_CONN(conn), OR_CONN_EVENT_NEW, 0);
return connection_tls_start_handshake(TO_OR_CONN(conn), 1);
case CONN_TYPE_AP:
switch (listener_type) {
TO_EDGE_CONN(conn)->isolation_flags = listener->isolation_flags;
TO_EDGE_CONN(conn)->session_group = listener->session_group;
TO_EDGE_CONN(conn)->nym_epoch = get_signewnym_epoch();
TO_EDGE_CONN(conn)->socks_request->listener_type = listener->_base.type;
switch (TO_CONN(listener)->type) {
case CONN_TYPE_AP_LISTENER:
conn->state = AP_CONN_STATE_SOCKS_WAIT;
break;
@@ -1741,6 +1715,113 @@ connection_read_proxy_handshake(connection_t *conn)
return ret;
}
/** Given a list of listener connections in <b>old_conns</b>, and list of
* port_cfg_t entries in <b>ports</b>, open a new listener for every port in
* <b>ports</b> that does not already have a listener in <b>old_conns</b>.
*
* Remove from <b>old_conns</b> every connection that has a corresponding
* entry in <b>ports</b>. Add to <b>new_conns</b> new every connection we
* launch.
*
* Return 0 on success, -1 on failure.
**/
static int
retry_listener_ports(smartlist_t *old_conns,
const smartlist_t *ports,
smartlist_t *new_conns)
{
smartlist_t *launch = smartlist_create();
int r = 0;
smartlist_add_all(launch, ports);
/* Iterate through old_conns, comparing it to launch: remove from both lists
* each pair of elements that corresponds to the same port. */
SMARTLIST_FOREACH_BEGIN(old_conns, connection_t *, conn) {
const port_cfg_t *found_port = NULL;
/* Okay, so this is a listener. Is it configured? */
SMARTLIST_FOREACH_BEGIN(launch, const port_cfg_t *, wanted) {
if (conn->type != wanted->type)
continue;
if ((conn->socket_family != AF_UNIX && wanted->is_unix_addr) ||
(conn->socket_family == AF_UNIX && ! wanted->is_unix_addr))
continue;
if (wanted->is_unix_addr) {
if (conn->socket_family == AF_UNIX &&
!strcmp(wanted->unix_addr, conn->address)) {
found_port = wanted;
break;
}
} else {
int port_matches;
if (wanted->port == CFG_AUTO_PORT) {
port_matches = 1;
} else {
port_matches = (wanted->port == conn->port);
}
if (port_matches && tor_addr_eq(&wanted->addr, &conn->addr)) {
found_port = wanted;
break;
}
}
} SMARTLIST_FOREACH_END(wanted);
if (found_port) {
/* This listener is already running; we don't need to launch it. */
//log_debug(LD_NET, "Already have %s on %s:%d",
// conn_type_to_string(found_port->type), conn->address, conn->port);
smartlist_remove(launch, found_port);
/* And we can remove the connection from old_conns too. */
SMARTLIST_DEL_CURRENT(old_conns, conn);
}
} SMARTLIST_FOREACH_END(conn);
/* Now open all the listeners that are configured but not opened. */
SMARTLIST_FOREACH_BEGIN(launch, const port_cfg_t *, port) {
struct sockaddr *listensockaddr;
socklen_t listensocklen = 0;
char *address=NULL;
connection_t *conn;
int real_port = port->port == CFG_AUTO_PORT ? 0 : port->port;
tor_assert(real_port <= UINT16_MAX);
if (port->is_unix_addr) {
listensockaddr = (struct sockaddr *)
create_unix_sockaddr(port->unix_addr,
&address, &listensocklen);
} else {
listensockaddr = tor_malloc(sizeof(struct sockaddr_storage));
listensocklen = tor_addr_to_sockaddr(&port->addr,
real_port,
listensockaddr,
sizeof(struct sockaddr_storage));
address = tor_dup_addr(&port->addr);
}
if (listensockaddr) {
conn = connection_create_listener(listensockaddr, listensocklen,
port->type, address, port);
tor_free(listensockaddr);
tor_free(address);
} else {
conn = NULL;
}
if (!conn) {
r = -1;
} else {
if (new_conns)
smartlist_add(new_conns, conn);
}
} SMARTLIST_FOREACH_END(port);
smartlist_free(launch);
return r;
}
/**
* Launch any configured listener connections of type <b>type</b>. (A
* listener is configured if <b>port_option</b> is non-zero. If any
@@ -1748,168 +1829,73 @@ connection_read_proxy_handshake(connection_t *conn)
* connection binding to each one. Otherwise, create a single
* connection binding to the address <b>default_addr</b>.)
*
* Only launch the listeners of this type that are not already open, and
* only close listeners that are no longer wanted. Existing listeners
* that are still configured are not touched.
* We assume that we're starting with a list of existing listener connection_t
* pointers in <b>old_conns</b>: we do not launch listeners that are already
* in that list. Instead, we just remove them from the list.
*
* If <b>disable_all_conns</b> is set, then never open new conns, and
* close the existing ones.
*
* Add all old conns that should be closed to <b>replaced_conns</b>.
* Add all new connections to <b>new_conns</b>.
* All new connections we launch are added to <b>new_conns</b>.
*/
static int
retry_listeners(int type, config_line_t *cfg,
retry_listeners(smartlist_t *old_conns,
int type, const config_line_t *cfg,
int port_option, const char *default_addr,
smartlist_t *replaced_conns,
smartlist_t *new_conns,
int disable_all_conns,
int socket_family)
int is_sockaddr_un)
{
smartlist_t *launch = smartlist_create(), *conns;
int free_launch_elts = 1;
int r;
config_line_t *c;
connection_t *conn;
config_line_t *line;
smartlist_t *ports = smartlist_create();
tor_addr_t dflt_addr;
int retval = 0;
tor_assert(socket_family == AF_INET || socket_family == AF_UNIX);
if (cfg && port_option) {
for (c = cfg; c; c = c->next) {
smartlist_add(launch, c);
}
free_launch_elts = 0;
} else if (port_option) {
line = tor_malloc_zero(sizeof(config_line_t));
line->key = tor_strdup("");
line->value = tor_strdup(default_addr);
smartlist_add(launch, line);
if (default_addr) {
tor_addr_from_str(&dflt_addr, default_addr);
} else {
tor_addr_make_unspec(&dflt_addr);
}
/*
SMARTLIST_FOREACH(launch, config_line_t *, l,
log_fn(LOG_NOTICE, "#%s#%s", l->key, l->value));
*/
conns = get_connection_array();
SMARTLIST_FOREACH(conns, connection_t *, conn,
{
if (conn->type != type ||
conn->socket_family != socket_family ||
conn->marked_for_close)
continue;
/* Okay, so this is a listener. Is it configured? */
line = NULL;
SMARTLIST_FOREACH(launch, config_line_t *, wanted,
{
char *address=NULL;
uint16_t port;
switch (socket_family) {
case AF_INET:
if (!parse_addr_port(LOG_WARN,
wanted->value, &address, NULL, &port)) {
int addr_matches = !strcasecmp(address, conn->address);
int port_matches;
tor_free(address);
if (port) {
/* The Listener line has a port */
port_matches = (port == conn->port);
} else if (port_option == CFG_AUTO_PORT) {
/* The Listener line has no port, and the Port line is "auto".
* "auto" matches anything; transitions from any port to
* "auto" succeed. */
port_matches = 1;
} else {
/* The Listener line has no port, and the Port line is "auto".
* "auto" matches anything; transitions from any port to
* "auto" succeed. */
port_matches = (port_option == conn->port);
}
if (port_matches && addr_matches) {
line = wanted;
break;
}
}
break;
case AF_UNIX:
if (!strcasecmp(wanted->value, conn->address)) {
line = wanted;
break;
}
break;
default:
tor_assert(0);
}
});
if (!line || disable_all_conns) {
/* This one isn't configured. Close it. */
log_notice(LD_NET, "Closing no-longer-configured %s on %s:%d",
conn_type_to_string(type), conn->address, conn->port);
if (replaced_conns) {
smartlist_add(replaced_conns, conn);
} else {
connection_close_immediate(conn);
connection_mark_for_close(conn);
}
if (port_option) {
if (!cfg) {
port_cfg_t *port = tor_malloc_zero(sizeof(port_cfg_t));
tor_addr_copy(&port->addr, &dflt_addr);
port->port = port_option;
port->type = type;
smartlist_add(ports, port);
} else {
/* It's configured; we don't need to launch it. */
// log_debug(LD_NET, "Already have %s on %s:%d",
// conn_type_to_string(type), conn->address, conn->port);
smartlist_remove(launch, line);
if (free_launch_elts)
config_free_lines(line);
}
});
/* Now open all the listeners that are configured but not opened. */
r = 0;
if (!disable_all_conns) {
SMARTLIST_FOREACH_BEGIN(launch, config_line_t *, cfg_line) {
char *address = NULL;
struct sockaddr *listensockaddr;
socklen_t listensocklen = 0;
switch (socket_family) {
case AF_INET:
listensockaddr = (struct sockaddr *)
create_inet_sockaddr(cfg_line->value,
port_option,
&address, &listensocklen);
break;
case AF_UNIX:
listensockaddr = (struct sockaddr *)
create_unix_sockaddr(cfg_line->value,
&address, &listensocklen);
break;
default:
tor_assert(0);
}
if (listensockaddr) {
conn = connection_create_listener(listensockaddr, listensocklen,
type, address);
tor_free(listensockaddr);
tor_free(address);
} else
conn = NULL;
if (!conn) {
r = -1;
const config_line_t *c;
for (c = cfg; c; c = c->next) {
port_cfg_t *port;
tor_addr_t addr;
uint16_t portval = 0;
if (is_sockaddr_un) {
size_t len = strlen(c->value);
port = tor_malloc_zero(sizeof(port_cfg_t) + len + 1);
port->is_unix_addr = 1;
memcpy(port->unix_addr, c->value, len+1);
} else {
if (new_conns)
smartlist_add(new_conns, conn);
if (tor_addr_port_parse(c->value, &addr, &portval) < 0) {
log_warn(LD_CONFIG, "Can't parse/resolve %s %s",
c->key, c->value);
retval = -1;
continue;
}
port = tor_malloc_zero(sizeof(port_cfg_t));
tor_addr_copy(&port->addr, &addr);
}
} SMARTLIST_FOREACH_END(cfg_line);
port->type = type;
port->port = portval ? portval : port_option;
smartlist_add(ports, port);
}
}
}
if (free_launch_elts) {
SMARTLIST_FOREACH(launch, config_line_t *, cfg_line,
config_free_lines(cfg_line));
}
smartlist_free(launch);
if (retval == -1)
goto cleanup;
return r;
retval = retry_listener_ports(old_conns, ports, new_conns);
cleanup:
SMARTLIST_FOREACH(ports, port_cfg_t *, p, tor_free(p));
smartlist_free(ports);
return retval;
}
/** Launch listeners for each port you should have open. Only launch
@@ -1923,54 +1909,62 @@ int
retry_all_listeners(smartlist_t *replaced_conns,
smartlist_t *new_conns)
{
smartlist_t *listeners = smartlist_create();
const or_options_t *options = get_options();
int retval = 0;
const uint16_t old_or_port = router_get_advertised_or_port(options);
const uint16_t old_dir_port = router_get_advertised_dir_port(options, 0);
if (retry_listeners(CONN_TYPE_OR_LISTENER, options->ORListenAddress,
options->ORPort, "0.0.0.0",
replaced_conns, new_conns, options->ClientOnly,
AF_INET)<0)
SMARTLIST_FOREACH_BEGIN(get_connection_array(), connection_t *, conn) {
if (connection_is_listener(conn) && !conn->marked_for_close)
smartlist_add(listeners, conn);
} SMARTLIST_FOREACH_END(conn);
if (! options->ClientOnly) {
if (retry_listeners(listeners,
CONN_TYPE_OR_LISTENER, options->ORListenAddress,
options->ORPort, "0.0.0.0",
new_conns, 0) < 0)
retval = -1;
if (retry_listeners(listeners,
CONN_TYPE_DIR_LISTENER, options->DirListenAddress,
options->DirPort, "0.0.0.0",
new_conns, 0) < 0)
retval = -1;
}
if (retry_listener_ports(listeners,
get_configured_client_ports(),
new_conns) < 0)
retval = -1;
if (retry_listeners(CONN_TYPE_DIR_LISTENER, options->DirListenAddress,
options->DirPort, "0.0.0.0",
replaced_conns, new_conns, options->ClientOnly,
AF_INET)<0)
retval = -1;
if (retry_listeners(CONN_TYPE_AP_LISTENER, options->SocksListenAddress,
options->SocksPort, "127.0.0.1",
replaced_conns, new_conns, 0,
AF_INET)<0)
retval = -1;
if (retry_listeners(CONN_TYPE_AP_TRANS_LISTENER, options->TransListenAddress,
options->TransPort, "127.0.0.1",
replaced_conns, new_conns, 0,
AF_INET)<0)
retval = -1;
if (retry_listeners(CONN_TYPE_AP_NATD_LISTENER, options->NATDListenAddress,
options->NATDPort, "127.0.0.1",
replaced_conns, new_conns, 0,
AF_INET)<0)
retval = -1;
if (retry_listeners(CONN_TYPE_AP_DNS_LISTENER, options->DNSListenAddress,
options->DNSPort, "127.0.0.1",
replaced_conns, new_conns, 0,
AF_INET)<0)
retval = -1;
if (retry_listeners(CONN_TYPE_CONTROL_LISTENER,
if (retry_listeners(listeners,
CONN_TYPE_CONTROL_LISTENER,
options->ControlListenAddress,
options->ControlPort, "127.0.0.1",
replaced_conns, new_conns, 0,
AF_INET)<0)
new_conns, 0) < 0)
return -1;
if (retry_listeners(CONN_TYPE_CONTROL_LISTENER,
if (retry_listeners(listeners,
CONN_TYPE_CONTROL_LISTENER,
options->ControlSocket,
options->ControlSocket ? 1 : 0, NULL,
replaced_conns, new_conns, 0,
AF_UNIX)<0)
new_conns, 1) < 0)
return -1;
/* Any members that were still in 'listeners' don't correspond to
* any configured port. Kill 'em. */
SMARTLIST_FOREACH_BEGIN(listeners, connection_t *, conn) {
log_notice(LD_NET, "Closing no-longer-configured %s on %s:%d",
conn_type_to_string(conn->type), conn->address, conn->port);
if (replaced_conns) {
smartlist_add(replaced_conns, conn);
} else {
connection_close_immediate(conn);
connection_mark_for_close(conn);
}
} SMARTLIST_FOREACH_END(conn);
smartlist_free(listeners);
if (old_or_port != router_get_advertised_or_port(options) ||
old_dir_port != router_get_advertised_dir_port(options, 0)) {
/* Our chosen ORPort or DirPort is not what it used to be: the
@@ -3910,6 +3904,9 @@ assert_connection_ok(connection_t *conn, time_t now)
case CONN_TYPE_CONTROL:
tor_assert(conn->magic == CONTROL_CONNECTION_MAGIC);
break;
CASE_ANY_LISTENER_TYPE:
tor_assert(conn->magic == LISTENER_CONNECTION_MAGIC);
break;
default:
tor_assert(conn->magic == BASE_CONNECTION_MAGIC);
break;
@@ -3994,13 +3991,7 @@ assert_connection_ok(connection_t *conn, time_t now)
switch (conn->type)
{
case CONN_TYPE_OR_LISTENER:
case CONN_TYPE_AP_LISTENER:
case CONN_TYPE_AP_TRANS_LISTENER:
case CONN_TYPE_AP_NATD_LISTENER:
case CONN_TYPE_DIR_LISTENER:
case CONN_TYPE_CONTROL_LISTENER:
case CONN_TYPE_AP_DNS_LISTENER:
CASE_ANY_LISTENER_TYPE:
tor_assert(conn->state == LISTENER_STATE_READY);
break;
case CONN_TYPE_OR:
@@ -4136,3 +4127,42 @@ proxy_type_to_string(int proxy_type)
return NULL; /*Unreached*/
}
/** Call _connection_free() on every connection in our array, and release all
* storage held by connection.c. This is used by cpuworkers and dnsworkers
* when they fork, so they don't keep resources held open (especially
* sockets).
*
* Don't do the checks in connection_free(), because they will
* fail.
*/
void
connection_free_all(void)
{
smartlist_t *conns = get_connection_array();
/* We don't want to log any messages to controllers. */
SMARTLIST_FOREACH(conns, connection_t *, conn,
if (conn->type == CONN_TYPE_CONTROL)
TO_CONTROL_CONN(conn)->event_mask = 0);
control_update_global_event_mask();
/* Unlink everything from the identity map. */
connection_or_clear_identity_map();
/* Clear out our list of broken connections */
clear_broken_connection_map(0);
SMARTLIST_FOREACH(conns, connection_t *, conn, _connection_free(conn));
if (outgoing_addrs) {
SMARTLIST_FOREACH(outgoing_addrs, void*, addr, tor_free(addr));
smartlist_free(outgoing_addrs);
outgoing_addrs = NULL;
}
#ifdef USE_BUFFEREVENTS
if (global_rate_limit)
bufferevent_rate_limit_group_free(global_rate_limit);
#endif
}
+1
View File
@@ -22,6 +22,7 @@ dir_connection_t *dir_connection_new(int socket_family);
or_connection_t *or_connection_new(int socket_family);
edge_connection_t *edge_connection_new(int type, int socket_family);
control_connection_t *control_connection_new(int socket_family);
listener_connection_t *listener_connection_new(int type, int socket_family);
connection_t *connection_new(int type, int socket_family);
void connection_link_connections(connection_t *conn_a, connection_t *conn_b);
+270 -3
View File
@@ -57,6 +57,7 @@ static int connection_exit_connect_dir(edge_connection_t *exitconn);
static int address_is_in_virtual_range(const char *addr);
static int consider_plaintext_ports(edge_connection_t *conn, uint16_t port);
static void clear_trackexithost_mappings(const char *exitname);
static int connection_ap_supports_optimistic_data(const edge_connection_t *);
/** An AP stream has failed/finished. If it hasn't already sent back
* a socks reply, send one now (based on endreason). Also set
@@ -154,10 +155,26 @@ connection_edge_process_inbuf(edge_connection_t *conn, int package_partial)
return -1;
}
return 0;
case AP_CONN_STATE_CONNECT_WAIT:
if (connection_ap_supports_optimistic_data(conn)) {
log_info(LD_EDGE,
"data from edge while in '%s' state. Sending it anyway. "
"package_partial=%d, buflen=%ld",
conn_state_to_string(conn->_base.type, conn->_base.state),
package_partial,
(long)connection_get_inbuf_len(TO_CONN(conn)));
if (connection_edge_package_raw_inbuf(conn, package_partial, NULL)<0) {
/* (We already sent an end cell if possible) */
connection_mark_for_close(TO_CONN(conn));
return -1;
}
return 0;
}
/* Fall through if the connection is on a circuit without optimistic
* data support. */
case EXIT_CONN_STATE_CONNECTING:
case AP_CONN_STATE_RENDDESC_WAIT:
case AP_CONN_STATE_CIRCUIT_WAIT:
case AP_CONN_STATE_CONNECT_WAIT:
case AP_CONN_STATE_RESOLVE_WAIT:
case AP_CONN_STATE_CONTROLLER_WAIT:
log_info(LD_EDGE,
@@ -722,6 +739,12 @@ connection_ap_detach_retriable(edge_connection_t *conn, origin_circuit_t *circ,
{
control_event_stream_status(conn, STREAM_EVENT_FAILED_RETRIABLE, reason);
conn->_base.timestamp_lastread = time(NULL);
if (conn->pending_optimistic_data) {
generic_buffer_set_to_copy(&conn->sending_optimistic_data,
conn->pending_optimistic_data);
}
if (!get_options()->LeaveStreamsUnattached || conn->use_begindir) {
/* If we're attaching streams ourself, or if this connection is
* a tunneled directory connection, then just attach it. */
@@ -1671,6 +1694,9 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
safe_str_client(socks->address),
socks->port);
if (! conn->original_dest_address)
conn->original_dest_address = tor_strdup(conn->socks_request->address);
if (socks->command == SOCKS_COMMAND_RESOLVE &&
!tor_inet_aton(socks->address, &addr_tmp) &&
options->AutomapHostsOnResolve && options->AutomapHostsSuffixes) {
@@ -2334,6 +2360,22 @@ get_unique_stream_id_by_circ(origin_circuit_t *circ)
return test_stream_id;
}
/** Return true iff <b>conn</b> is linked to a circuit and configured to use
* an exit that supports optimistic data. */
static int
connection_ap_supports_optimistic_data(const edge_connection_t *conn)
{
tor_assert(conn->_base.type == CONN_TYPE_AP);
/* We can only send optimistic data if we're connected to an open
general circuit. */
if (conn->on_circuit == NULL ||
conn->on_circuit->state != CIRCUIT_STATE_OPEN ||
conn->on_circuit->purpose != CIRCUIT_PURPOSE_C_GENERAL)
return 0;
return conn->may_use_optimistic_data;
}
/** Write a relay begin cell, using destaddr and destport from ap_conn's
* socks_request field, and send it down circ.
*
@@ -2395,6 +2437,21 @@ connection_ap_handshake_send_begin(edge_connection_t *ap_conn)
log_info(LD_APP,"Address/port sent, ap socket %d, n_circ_id %d",
ap_conn->_base.s, circ->_base.n_circ_id);
control_event_stream_status(ap_conn, STREAM_EVENT_SENT_CONNECT, 0);
/* If there's queued-up data, send it now */
if ((connection_get_inbuf_len(TO_CONN(ap_conn)) ||
ap_conn->sending_optimistic_data) &&
connection_ap_supports_optimistic_data(ap_conn)) {
log_info(LD_APP, "Sending up to %ld + %ld bytes of queued-up data",
(long)connection_get_inbuf_len(TO_CONN(ap_conn)),
ap_conn->sending_optimistic_data ?
(long)generic_buffer_len(ap_conn->sending_optimistic_data) :
0);
if (connection_edge_package_raw_inbuf(ap_conn, 1, NULL) < 0) {
connection_mark_for_close(TO_CONN(ap_conn));
}
}
return 0;
}
@@ -2494,7 +2551,9 @@ connection_ap_handshake_send_resolve(edge_connection_t *ap_conn)
edge_connection_t *
connection_ap_make_link(connection_t *partner,
char *address, uint16_t port,
const char *digest, int use_begindir, int want_onehop)
const char *digest,
int session_group, int isolation_flags,
int use_begindir, int want_onehop)
{
edge_connection_t *conn;
@@ -2524,6 +2583,12 @@ connection_ap_make_link(connection_t *partner,
digest, DIGEST_LEN);
}
/* Populate isolation fields. */
conn->socks_request->listener_type = CONN_TYPE_DIR_LISTENER;
conn->original_dest_address = tor_strdup(address);
conn->session_group = session_group;
conn->isolation_flags = isolation_flags;
conn->_base.address = tor_strdup("(Tor_internal)");
tor_addr_make_unspec(&conn->_base.addr);
conn->_base.port = 0;
@@ -3166,7 +3231,7 @@ connection_edge_is_rendezvous_stream(edge_connection_t *conn)
* resolved.)
*/
int
connection_ap_can_use_exit(edge_connection_t *conn, const node_t *exit)
connection_ap_can_use_exit(const edge_connection_t *conn, const node_t *exit)
{
const or_options_t *options = get_options();
@@ -3266,3 +3331,205 @@ parse_extended_hostname(char *address, int allowdotexit)
return BAD_HOSTNAME;
}
/** Return true iff the (possibly NULL) <b>alen</b>-byte chunk of memory at
* <b>a</b> is equal to the (possibly NULL) <b>blen</b>-byte chunk of memory
* at <b>b</b>. */
static int
memeq_opt(const char *a, size_t alen, const char *b, size_t blen)
{
if (a == NULL) {
return (b == NULL);
} else if (b == NULL) {
return 0;
} else if (alen != blen) {
return 0;
} else {
return tor_memeq(a, b, alen);
}
}
/**
* Return true iff none of the isolation flags and fields in <b>conn</b>
* should prevent it from being attached to <b>circ</b>.
*/
int
connection_edge_compatible_with_circuit(const edge_connection_t *conn,
const origin_circuit_t *circ)
{
const uint8_t iso = conn->isolation_flags;
const socks_request_t *sr = conn->socks_request;
/* If circ has never been used for an isolated connection, we can
* totally use it for this one. */
if (!circ->isolation_values_set)
return 1;
/* If circ has been used for connections having more than one value
* for some field f, it will have the corresponding bit set in
* isolation_flags_mixed. If isolation_flags_mixed has any bits
* in common with iso, then conn must be isolated from at least
* one stream that has been attached to circ. */
if ((iso & circ->isolation_flags_mixed) != 0) {
/* For at least one field where conn is isolated, the circuit
* already has mixed streams. */
return 0;
}
if (! conn->original_dest_address) {
log_warn(LD_BUG, "Reached connection_edge_compatible_with_circuit without "
"having set conn->original_dest_address");
((edge_connection_t*)conn)->original_dest_address =
tor_strdup(conn->socks_request->address);
}
if ((iso & ISO_STREAM) &&
(circ->associated_isolated_stream_global_id !=
TO_CONN(conn)->global_identifier))
return 0;
if ((iso & ISO_DESTPORT) && conn->socks_request->port != circ->dest_port)
return 0;
if ((iso & ISO_DESTADDR) &&
strcasecmp(conn->original_dest_address, circ->dest_address))
return 0;
if ((iso & ISO_SOCKSAUTH) &&
(! memeq_opt(sr->username, sr->usernamelen,
circ->socks_username, circ->socks_username_len) ||
! memeq_opt(sr->password, sr->passwordlen,
circ->socks_password, circ->socks_password_len)))
return 0;
if ((iso & ISO_CLIENTPROTO) &&
(conn->socks_request->listener_type != circ->client_proto_type ||
conn->socks_request->socks_version != circ->client_proto_socksver))
return 0;
if ((iso & ISO_CLIENTADDR) &&
!tor_addr_eq(&TO_CONN(conn)->addr, &circ->client_addr))
return 0;
if ((iso & ISO_SESSIONGRP) && conn->session_group != circ->session_group)
return 0;
if ((iso & ISO_NYM_EPOCH) && conn->nym_epoch != circ->nym_epoch)
return 0;
return 1;
}
/**
* If <b>dry_run</b> is false, update <b>circ</b>'s isolation flags and fields
* to reflect having had <b>conn</b> attached to it, and return 0. Otherwise,
* if <b>dry_run</b> is true, then make no changes to <b>circ</b>, and return
* a bitfield of isolation flags that we would have to set in
* isolation_flags_mixed to add <b>conn</b> to <b>circ</b>, or -1 if
* <b>circ</b> has had no streams attached to it.
*/
int
connection_edge_update_circuit_isolation(const edge_connection_t *conn,
origin_circuit_t *circ,
int dry_run)
{
const socks_request_t *sr = conn->socks_request;
if (! conn->original_dest_address) {
log_warn(LD_BUG, "Reached connection_update_circuit_isolation without "
"having set conn->original_dest_address");
((edge_connection_t*)conn)->original_dest_address =
tor_strdup(conn->socks_request->address);
}
if (!circ->isolation_values_set) {
if (dry_run)
return -1;
circ->associated_isolated_stream_global_id =
TO_CONN(conn)->global_identifier;
circ->dest_port = conn->socks_request->port;
circ->dest_address = tor_strdup(conn->original_dest_address);
circ->client_proto_type = conn->socks_request->listener_type;
circ->client_proto_socksver = conn->socks_request->socks_version;
tor_addr_copy(&circ->client_addr, &TO_CONN(conn)->addr);
circ->session_group = conn->session_group;
circ->nym_epoch = conn->nym_epoch;
circ->socks_username = sr->username ?
tor_memdup(sr->username, sr->usernamelen) : NULL;
circ->socks_password = sr->password ?
tor_memdup(sr->password, sr->passwordlen) : NULL;
circ->socks_username_len = sr->usernamelen;
circ->socks_password_len = sr->passwordlen;
circ->isolation_values_set = 1;
return 0;
} else {
uint8_t mixed = 0;
if (conn->socks_request->port != circ->dest_port)
mixed |= ISO_DESTPORT;
if (strcasecmp(conn->original_dest_address, circ->dest_address))
mixed |= ISO_DESTADDR;
if (!memeq_opt(sr->username, sr->usernamelen,
circ->socks_username, circ->socks_username_len) ||
!memeq_opt(sr->password, sr->passwordlen,
circ->socks_password, circ->socks_password_len))
mixed |= ISO_SOCKSAUTH;
if ((conn->socks_request->listener_type != circ->client_proto_type ||
conn->socks_request->socks_version != circ->client_proto_socksver))
mixed |= ISO_CLIENTPROTO;
if (!tor_addr_eq(&TO_CONN(conn)->addr, &circ->client_addr))
mixed |= ISO_CLIENTADDR;
if (conn->session_group != circ->session_group)
mixed |= ISO_SESSIONGRP;
if (conn->nym_epoch != circ->nym_epoch)
mixed |= ISO_NYM_EPOCH;
if (dry_run)
return mixed;
if ((mixed & conn->isolation_flags) != 0) {
log_warn(LD_BUG, "Updating a circuit with seemingly incompatible "
"isolation flags.");
}
circ->isolation_flags_mixed |= mixed;
return 0;
}
}
/**
* Clear the isolation settings on <b>circ</b>.
*
* This only works on an open circuit that has never had a stream attached to
* it, and whose isolation settings are hypothetical. (We set hypothetical
* isolation settings on circuits as we're launching them, so that we
* know whether they can handle more streams or whether we need to launch
* even more circuits. Once the circuit is open, if it turns out that
* we no longer have any streams to attach to it, we clear the isolation flags
* and data so that other streams can have a chance.)
*/
void
circuit_clear_isolation(origin_circuit_t *circ)
{
if (circ->isolation_any_streams_attached) {
log_warn(LD_BUG, "Tried to clear the isolation status of a dirty circuit");
return;
}
if (TO_CIRCUIT(circ)->state != CIRCUIT_STATE_OPEN) {
log_warn(LD_BUG, "Tried to clear the isolation status of a non-open "
"circuit");
return;
}
circ->isolation_values_set = 0;
circ->isolation_flags_mixed = 0;
circ->associated_isolated_stream_global_id = 0;
circ->client_proto_type = 0;
circ->client_proto_socksver = 0;
circ->dest_port = 0;
tor_addr_make_unspec(&circ->client_addr);
tor_free(circ->dest_address);
circ->session_group = -1;
circ->nym_epoch = 0;
if (circ->socks_username) {
memset(circ->socks_username, 0x11, circ->socks_username_len);
tor_free(circ->socks_username);
}
if (circ->socks_password) {
memset(circ->socks_password, 0x05, circ->socks_password_len);
tor_free(circ->socks_password);
}
circ->socks_username_len = circ->socks_password_len = 0;
}
+10 -1
View File
@@ -36,6 +36,8 @@ int connection_ap_handshake_send_resolve(edge_connection_t *ap_conn);
edge_connection_t *connection_ap_make_link(connection_t *partner,
char *address, uint16_t port,
const char *digest,
int session_group,
int isolation_flags,
int use_begindir, int want_onehop);
void connection_ap_handshake_socks_reply(edge_connection_t *conn, char *reply,
size_t replylen,
@@ -51,7 +53,7 @@ int connection_exit_begin_conn(cell_t *cell, circuit_t *circ);
int connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ);
void connection_exit_connect(edge_connection_t *conn);
int connection_edge_is_rendezvous_stream(edge_connection_t *conn);
int connection_ap_can_use_exit(edge_connection_t *conn,
int connection_ap_can_use_exit(const edge_connection_t *conn,
const node_t *exit);
void connection_ap_expire_beginning(void);
void connection_ap_attach_pending(void);
@@ -103,5 +105,12 @@ hostname_type_t parse_extended_hostname(char *address, int allowdotexit);
int get_pf_socket(void);
#endif
int connection_edge_compatible_with_circuit(const edge_connection_t *conn,
const origin_circuit_t *circ);
int connection_edge_update_circuit_isolation(const edge_connection_t *conn,
origin_circuit_t *circ,
int dry_run);
void circuit_clear_isolation(origin_circuit_t *circ);
#endif
+37 -2
View File
@@ -74,7 +74,8 @@
#define EVENT_NEWCONSENSUS 0x0016
#define EVENT_BUILDTIMEOUT_SET 0x0017
#define EVENT_SIGNAL 0x0018
#define _EVENT_MAX 0x0018
#define EVENT_CONF_CHANGED 0x0019
#define _EVENT_MAX 0x0019
/* If _EVENT_MAX ever hits 0x0020, we need to make the mask wider. */
/** Bitfield: The bit 1&lt;&lt;e is set if <b>any</b> open control
@@ -946,6 +947,7 @@ static const struct control_event_t control_event_table[] = {
{ EVENT_NEWCONSENSUS, "NEWCONSENSUS" },
{ EVENT_BUILDTIMEOUT_SET, "BUILDTIMEOUT_SET" },
{ EVENT_SIGNAL, "SIGNAL" },
{ EVENT_CONF_CHANGED, "CONF_CHANGED"},
{ 0, NULL },
};
@@ -3567,7 +3569,7 @@ control_event_logmsg(int severity, uint32_t domain, const char *msg)
severity <= LOG_NOTICE) {
char *esc = esc_for_log(msg);
++disable_log_messages;
control_event_general_status(severity, "BUG REASON=\"%s\"", esc);
control_event_general_status(severity, "BUG REASON=%s", esc);
--disable_log_messages;
tor_free(esc);
}
@@ -3996,6 +3998,39 @@ control_event_guard(const char *nickname, const char *digest,
return 0;
}
/** Called when a configuration option changes. This is generally triggered
* by SETCONF requests and RELOAD/SIGHUP signals. The <b>elements</b> is
* a smartlist_t containing (key, value, ...) pairs in sequence.
* <b>value</b> can be NULL. */
int
control_event_conf_changed(smartlist_t *elements)
{
int i;
char *result;
smartlist_t *lines;
if (!EVENT_IS_INTERESTING(EVENT_CONF_CHANGED) ||
smartlist_len(elements) == 0) {
return 0;
}
lines = smartlist_create();
for (i = 0; i < smartlist_len(elements); i += 2) {
char *k = smartlist_get(elements, i);
char *v = smartlist_get(elements, i+1);
if (v == NULL) {
smartlist_asprintf_add(lines, "650-%s", k);
} else {
smartlist_asprintf_add(lines, "650-%s=%s", k, v);
}
}
result = smartlist_join_strings(lines, "\r\n", 0, NULL);
send_control_event(EVENT_CONF_CHANGED, 0,
"650-CONF_CHANGED\r\n%s\r\n650 OK\r\n", result);
tor_free(result);
SMARTLIST_FOREACH(lines, char *, cp, tor_free(cp));
smartlist_free(lines);
return 0;
}
/** Helper: Return a newly allocated string containing a path to the
* file where we store our authentication cookie. */
static char *
+1
View File
@@ -66,6 +66,7 @@ int control_event_server_status(int severity, const char *format, ...)
CHECK_PRINTF(2,3);
int control_event_guard(const char *nickname, const char *digest,
const char *status);
int control_event_conf_changed(smartlist_t *elements);
int control_event_buildtimeout_set(const circuit_build_times_t *cbt,
buildtimeout_set_event_t type);
int control_event_signal(uintptr_t signal);
+7 -1
View File
@@ -973,6 +973,10 @@ directory_initiate_command_rend(const char *address, const tor_addr_t *_addr,
}
} else { /* we want to connect via a tor connection */
edge_connection_t *linked_conn;
/* Anonymized tunneled connections can never share a circuit.
* One-hop directory connections can share circuits with each other
* but nothing else. */
int iso_flags = anonymized_connection ? ISO_STREAM : ISO_SESSIONGRP;
/* If it's an anonymized connection, remember the fact that we
* wanted it for later: maybe we'll want it again soon. */
@@ -988,7 +992,9 @@ directory_initiate_command_rend(const char *address, const tor_addr_t *_addr,
linked_conn =
connection_ap_make_link(TO_CONN(conn),
conn->_base.address, conn->_base.port,
digest, use_begindir, conn->dirconn_direct);
digest,
SESSION_GROUP_DIRCONN, iso_flags,
use_begindir, conn->dirconn_direct);
if (!linked_conn) {
log_warn(LD_NET,"Making tunnel to dirserver failed.");
connection_mark_for_close(TO_CONN(conn));
+24 -7
View File
@@ -29,8 +29,9 @@
* DNSPort. We need to eventually answer the request <b>req</b>.
*/
static void
evdns_server_callback(struct evdns_server_request *req, void *_data)
evdns_server_callback(struct evdns_server_request *req, void *data_)
{
const listener_connection_t *listener = data_;
edge_connection_t *conn;
int i = 0;
struct evdns_server_question *q = NULL;
@@ -43,7 +44,7 @@ evdns_server_callback(struct evdns_server_request *req, void *_data)
char *q_name;
tor_assert(req);
tor_assert(_data == NULL);
log_info(LD_APP, "Got a new DNS request!");
req->flags |= 0x80; /* set RA */
@@ -130,7 +131,11 @@ evdns_server_callback(struct evdns_server_request *req, void *_data)
strlcpy(conn->socks_request->address, q->name,
sizeof(conn->socks_request->address));
conn->socks_request->listener_type = listener->_base.type;
conn->dns_server_request = req;
conn->isolation_flags = listener->isolation_flags;
conn->session_group = listener->session_group;
conn->nym_epoch = get_signewnym_epoch();
if (connection_add(TO_CONN(conn)) < 0) {
log_warn(LD_APP, "Couldn't register dummy connection for DNS request");
@@ -181,6 +186,12 @@ dnsserv_launch_request(const char *name, int reverse)
strlcpy(conn->socks_request->address, name,
sizeof(conn->socks_request->address));
conn->socks_request->listener_type = CONN_TYPE_CONTROL_LISTENER;
conn->original_dest_address = tor_strdup(name);
conn->session_group = SESSION_GROUP_CONTROL_RESOLVE;
conn->nym_epoch = get_signewnym_epoch();
conn->isolation_flags = ISO_DEFAULT;
if (connection_add(TO_CONN(conn))<0) {
log_warn(LD_APP, "Couldn't register dummy connection for RESOLVE request");
connection_free(TO_CONN(conn));
@@ -305,12 +316,15 @@ dnsserv_resolved(edge_connection_t *conn,
void
dnsserv_configure_listener(connection_t *conn)
{
listener_connection_t *listener_conn;
tor_assert(conn);
tor_assert(SOCKET_OK(conn->s));
tor_assert(conn->type == CONN_TYPE_AP_DNS_LISTENER);
conn->dns_server_port =
tor_evdns_add_server_port(conn->s, 0, evdns_server_callback, NULL);
listener_conn = TO_LISTENER_CONN(conn);
listener_conn->dns_server_port =
tor_evdns_add_server_port(conn->s, 0, evdns_server_callback,
listener_conn);
}
/** Free the evdns server port for <b>conn</b>, which must be an
@@ -318,12 +332,15 @@ dnsserv_configure_listener(connection_t *conn)
void
dnsserv_close_listener(connection_t *conn)
{
listener_connection_t *listener_conn;
tor_assert(conn);
tor_assert(conn->type == CONN_TYPE_AP_DNS_LISTENER);
if (conn->dns_server_port) {
evdns_close_server_port(conn->dns_server_port);
conn->dns_server_port = NULL;
listener_conn = TO_LISTENER_CONN(conn);
if (listener_conn->dns_server_port) {
evdns_close_server_port(listener_conn->dns_server_port);
listener_conn->dns_server_port = NULL;
}
}
+188 -128
View File
@@ -930,10 +930,9 @@ geoip_dirreq_stats_init(time_t now)
start_of_dirreq_stats_interval = now;
}
/** Stop collecting directory request stats in a way that we can re-start
* doing so in geoip_dirreq_stats_init(). */
/** Reset counters for dirreq stats. */
void
geoip_dirreq_stats_term(void)
geoip_reset_dirreq_stats(time_t now)
{
SMARTLIST_FOREACH(geoip_countries, geoip_country_t *, c, {
c->n_v2_ns_requests = c->n_v3_ns_requests = 0;
@@ -965,21 +964,131 @@ geoip_dirreq_stats_term(void)
tor_free(this);
}
}
start_of_dirreq_stats_interval = 0;
start_of_dirreq_stats_interval = now;
}
/** Write dirreq statistics to $DATADIR/stats/dirreq-stats and return when
* we would next want to write. */
/** Stop collecting directory request stats in a way that we can re-start
* doing so in geoip_dirreq_stats_init(). */
void
geoip_dirreq_stats_term(void)
{
geoip_reset_dirreq_stats(0);
}
/** Return a newly allocated string containing the dirreq statistics
* until <b>now</b>, or NULL if we're not collecting dirreq stats. */
char *
geoip_format_dirreq_stats(time_t now)
{
char t[ISO_TIME_LEN+1];
double v2_share = 0.0, v3_share = 0.0;
int i;
char *v3_ips_string, *v2_ips_string, *v3_reqs_string, *v2_reqs_string,
*v2_share_string = NULL, *v3_share_string = NULL,
*v3_direct_dl_string, *v2_direct_dl_string,
*v3_tunneled_dl_string, *v2_tunneled_dl_string;
char *result;
if (!start_of_dirreq_stats_interval)
return NULL; /* Not initialized. */
format_iso_time(t, now);
v2_ips_string = geoip_get_client_history(GEOIP_CLIENT_NETWORKSTATUS_V2);
v3_ips_string = geoip_get_client_history(GEOIP_CLIENT_NETWORKSTATUS);
v2_reqs_string = geoip_get_request_history(
GEOIP_CLIENT_NETWORKSTATUS_V2);
v3_reqs_string = geoip_get_request_history(GEOIP_CLIENT_NETWORKSTATUS);
#define RESPONSE_GRANULARITY 8
for (i = 0; i < GEOIP_NS_RESPONSE_NUM; i++) {
ns_v2_responses[i] = round_uint32_to_next_multiple_of(
ns_v2_responses[i], RESPONSE_GRANULARITY);
ns_v3_responses[i] = round_uint32_to_next_multiple_of(
ns_v3_responses[i], RESPONSE_GRANULARITY);
}
#undef RESPONSE_GRANULARITY
if (!geoip_get_mean_shares(now, &v2_share, &v3_share)) {
tor_asprintf(&v2_share_string, "dirreq-v2-share %0.2lf%%\n",
v2_share*100);
tor_asprintf(&v3_share_string, "dirreq-v3-share %0.2lf%%\n",
v3_share*100);
}
v2_direct_dl_string = geoip_get_dirreq_history(
GEOIP_CLIENT_NETWORKSTATUS_V2, DIRREQ_DIRECT);
v3_direct_dl_string = geoip_get_dirreq_history(
GEOIP_CLIENT_NETWORKSTATUS, DIRREQ_DIRECT);
v2_tunneled_dl_string = geoip_get_dirreq_history(
GEOIP_CLIENT_NETWORKSTATUS_V2, DIRREQ_TUNNELED);
v3_tunneled_dl_string = geoip_get_dirreq_history(
GEOIP_CLIENT_NETWORKSTATUS, DIRREQ_TUNNELED);
/* Put everything together into a single string. */
tor_asprintf(&result, "dirreq-stats-end %s (%d s)\n"
"dirreq-v3-ips %s\n"
"dirreq-v2-ips %s\n"
"dirreq-v3-reqs %s\n"
"dirreq-v2-reqs %s\n"
"dirreq-v3-resp ok=%u,not-enough-sigs=%u,unavailable=%u,"
"not-found=%u,not-modified=%u,busy=%u\n"
"dirreq-v2-resp ok=%u,unavailable=%u,"
"not-found=%u,not-modified=%u,busy=%u\n"
"%s"
"%s"
"dirreq-v3-direct-dl %s\n"
"dirreq-v2-direct-dl %s\n"
"dirreq-v3-tunneled-dl %s\n"
"dirreq-v2-tunneled-dl %s\n",
t,
(unsigned) (now - start_of_dirreq_stats_interval),
v3_ips_string ? v3_ips_string : "",
v2_ips_string ? v2_ips_string : "",
v3_reqs_string ? v3_reqs_string : "",
v2_reqs_string ? v2_reqs_string : "",
ns_v3_responses[GEOIP_SUCCESS],
ns_v3_responses[GEOIP_REJECT_NOT_ENOUGH_SIGS],
ns_v3_responses[GEOIP_REJECT_UNAVAILABLE],
ns_v3_responses[GEOIP_REJECT_NOT_FOUND],
ns_v3_responses[GEOIP_REJECT_NOT_MODIFIED],
ns_v3_responses[GEOIP_REJECT_BUSY],
ns_v2_responses[GEOIP_SUCCESS],
ns_v2_responses[GEOIP_REJECT_UNAVAILABLE],
ns_v2_responses[GEOIP_REJECT_NOT_FOUND],
ns_v2_responses[GEOIP_REJECT_NOT_MODIFIED],
ns_v2_responses[GEOIP_REJECT_BUSY],
v2_share_string ? v2_share_string : "",
v3_share_string ? v3_share_string : "",
v3_direct_dl_string ? v3_direct_dl_string : "",
v2_direct_dl_string ? v2_direct_dl_string : "",
v3_tunneled_dl_string ? v3_tunneled_dl_string : "",
v2_tunneled_dl_string ? v2_tunneled_dl_string : "");
/* Free partial strings. */
tor_free(v3_ips_string);
tor_free(v2_ips_string);
tor_free(v3_reqs_string);
tor_free(v2_reqs_string);
tor_free(v2_share_string);
tor_free(v3_share_string);
tor_free(v3_direct_dl_string);
tor_free(v2_direct_dl_string);
tor_free(v3_tunneled_dl_string);
tor_free(v2_tunneled_dl_string);
return result;
}
/** If 24 hours have passed since the beginning of the current dirreq
* stats period, write dirreq stats to $DATADIR/stats/dirreq-stats
* (possibly overwriting an existing file) and reset counters. Return
* when we would next want to write dirreq stats or 0 if we never want to
* write. */
time_t
geoip_dirreq_stats_write(time_t now)
{
char *statsdir = NULL, *filename = NULL;
char *data_v2 = NULL, *data_v3 = NULL;
char written[ISO_TIME_LEN+1];
open_file_t *open_file = NULL;
double v2_share = 0.0, v3_share = 0.0;
FILE *out;
int i;
char *statsdir = NULL, *filename = NULL, *str = NULL;
if (!start_of_dirreq_stats_interval)
return 0; /* Not initialized. */
@@ -989,98 +1098,26 @@ geoip_dirreq_stats_write(time_t now)
/* Discard all items in the client history that are too old. */
geoip_remove_old_clients(start_of_dirreq_stats_interval);
/* Generate history string .*/
str = geoip_format_dirreq_stats(now);
/* Write dirreq-stats string to disk. */
statsdir = get_datadir_fname("stats");
if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0)
if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) {
log_warn(LD_HIST, "Unable to create stats/ directory!");
goto done;
}
filename = get_datadir_fname2("stats", "dirreq-stats");
data_v2 = geoip_get_client_history(GEOIP_CLIENT_NETWORKSTATUS_V2);
data_v3 = geoip_get_client_history(GEOIP_CLIENT_NETWORKSTATUS);
format_iso_time(written, now);
out = start_writing_to_stdio_file(filename, OPEN_FLAGS_APPEND | O_TEXT,
0600, &open_file);
if (!out)
goto done;
if (fprintf(out, "dirreq-stats-end %s (%d s)\ndirreq-v3-ips %s\n"
"dirreq-v2-ips %s\n", written,
(unsigned) (now - start_of_dirreq_stats_interval),
data_v3 ? data_v3 : "", data_v2 ? data_v2 : "") < 0)
goto done;
tor_free(data_v2);
tor_free(data_v3);
if (write_str_to_file(filename, str, 0) < 0)
log_warn(LD_HIST, "Unable to write dirreq statistics to disk!");
data_v2 = geoip_get_request_history(GEOIP_CLIENT_NETWORKSTATUS_V2);
data_v3 = geoip_get_request_history(GEOIP_CLIENT_NETWORKSTATUS);
if (fprintf(out, "dirreq-v3-reqs %s\ndirreq-v2-reqs %s\n",
data_v3 ? data_v3 : "", data_v2 ? data_v2 : "") < 0)
goto done;
tor_free(data_v2);
tor_free(data_v3);
SMARTLIST_FOREACH(geoip_countries, geoip_country_t *, c, {
c->n_v2_ns_requests = c->n_v3_ns_requests = 0;
});
#define RESPONSE_GRANULARITY 8
for (i = 0; i < GEOIP_NS_RESPONSE_NUM; i++) {
ns_v2_responses[i] = round_uint32_to_next_multiple_of(
ns_v2_responses[i], RESPONSE_GRANULARITY);
ns_v3_responses[i] = round_uint32_to_next_multiple_of(
ns_v3_responses[i], RESPONSE_GRANULARITY);
}
#undef RESPONSE_GRANULARITY
if (fprintf(out, "dirreq-v3-resp ok=%u,not-enough-sigs=%u,unavailable=%u,"
"not-found=%u,not-modified=%u,busy=%u\n",
ns_v3_responses[GEOIP_SUCCESS],
ns_v3_responses[GEOIP_REJECT_NOT_ENOUGH_SIGS],
ns_v3_responses[GEOIP_REJECT_UNAVAILABLE],
ns_v3_responses[GEOIP_REJECT_NOT_FOUND],
ns_v3_responses[GEOIP_REJECT_NOT_MODIFIED],
ns_v3_responses[GEOIP_REJECT_BUSY]) < 0)
goto done;
if (fprintf(out, "dirreq-v2-resp ok=%u,unavailable=%u,"
"not-found=%u,not-modified=%u,busy=%u\n",
ns_v2_responses[GEOIP_SUCCESS],
ns_v2_responses[GEOIP_REJECT_UNAVAILABLE],
ns_v2_responses[GEOIP_REJECT_NOT_FOUND],
ns_v2_responses[GEOIP_REJECT_NOT_MODIFIED],
ns_v2_responses[GEOIP_REJECT_BUSY]) < 0)
goto done;
memset(ns_v2_responses, 0, sizeof(ns_v2_responses));
memset(ns_v3_responses, 0, sizeof(ns_v3_responses));
if (!geoip_get_mean_shares(now, &v2_share, &v3_share)) {
if (fprintf(out, "dirreq-v2-share %0.2lf%%\n", v2_share*100) < 0)
goto done;
if (fprintf(out, "dirreq-v3-share %0.2lf%%\n", v3_share*100) < 0)
goto done;
}
data_v2 = geoip_get_dirreq_history(GEOIP_CLIENT_NETWORKSTATUS_V2,
DIRREQ_DIRECT);
data_v3 = geoip_get_dirreq_history(GEOIP_CLIENT_NETWORKSTATUS,
DIRREQ_DIRECT);
if (fprintf(out, "dirreq-v3-direct-dl %s\ndirreq-v2-direct-dl %s\n",
data_v3 ? data_v3 : "", data_v2 ? data_v2 : "") < 0)
goto done;
tor_free(data_v2);
tor_free(data_v3);
data_v2 = geoip_get_dirreq_history(GEOIP_CLIENT_NETWORKSTATUS_V2,
DIRREQ_TUNNELED);
data_v3 = geoip_get_dirreq_history(GEOIP_CLIENT_NETWORKSTATUS,
DIRREQ_TUNNELED);
if (fprintf(out, "dirreq-v3-tunneled-dl %s\ndirreq-v2-tunneled-dl %s\n",
data_v3 ? data_v3 : "", data_v2 ? data_v2 : "") < 0)
goto done;
finish_writing_to_file(open_file);
open_file = NULL;
start_of_dirreq_stats_interval = now;
/* Reset measurement interval start. */
geoip_reset_dirreq_stats(now);
done:
if (open_file)
abort_writing_to_file(open_file);
tor_free(filename);
tor_free(statsdir);
tor_free(data_v2);
tor_free(data_v3);
tor_free(filename);
tor_free(str);
return start_of_dirreq_stats_interval + WRITE_STATS_INTERVAL;
}
@@ -1160,8 +1197,8 @@ static char *bridge_stats_extrainfo = NULL;
/** Return a newly allocated string holding our bridge usage stats by country
* in a format suitable for inclusion in an extrainfo document. Return NULL on
* failure. */
static char *
format_bridge_stats_extrainfo(time_t now)
char *
geoip_format_bridge_stats(time_t now)
{
char *out = NULL, *data = NULL;
long duration = now - start_of_bridge_stats_interval;
@@ -1169,6 +1206,8 @@ format_bridge_stats_extrainfo(time_t now)
if (duration < 0)
return NULL;
if (!start_of_bridge_stats_interval)
return NULL; /* Not initialized. */
format_iso_time(written, now);
data = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
@@ -1218,7 +1257,7 @@ geoip_bridge_stats_write(time_t now)
geoip_remove_old_clients(start_of_bridge_stats_interval);
/* Generate formatted string */
val = format_bridge_stats_extrainfo(now);
val = geoip_format_bridge_stats(now);
if (val == NULL)
goto done;
@@ -1295,25 +1334,51 @@ geoip_entry_stats_init(time_t now)
start_of_entry_stats_interval = now;
}
/** Reset counters for entry stats. */
void
geoip_reset_entry_stats(time_t now)
{
client_history_clear();
start_of_entry_stats_interval = now;
}
/** Stop collecting entry stats in a way that we can re-start doing so in
* geoip_entry_stats_init(). */
void
geoip_entry_stats_term(void)
{
client_history_clear();
start_of_entry_stats_interval = 0;
geoip_reset_entry_stats(0);
}
/** Write entry statistics to $DATADIR/stats/entry-stats and return time
* when we would next want to write. */
/** Return a newly allocated string containing the entry statistics
* until <b>now</b>, or NULL if we're not collecting entry stats. */
char *
geoip_format_entry_stats(time_t now)
{
char t[ISO_TIME_LEN+1];
char *data = NULL;
char *result;
if (!start_of_entry_stats_interval)
return NULL; /* Not initialized. */
data = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
format_iso_time(t, now);
tor_asprintf(&result, "entry-stats-end %s (%u s)\nentry-ips %s\n",
t, (unsigned) (now - start_of_entry_stats_interval),
data ? data : "");
tor_free(data);
return result;
}
/** If 24 hours have passed since the beginning of the current entry stats
* period, write entry stats to $DATADIR/stats/entry-stats (possibly
* overwriting an existing file) and reset counters. Return when we would
* next want to write entry stats or 0 if we never want to write. */
time_t
geoip_entry_stats_write(time_t now)
{
char *statsdir = NULL, *filename = NULL;
char *data = NULL;
char written[ISO_TIME_LEN+1];
open_file_t *open_file = NULL;
FILE *out;
char *statsdir = NULL, *filename = NULL, *str = NULL;
if (!start_of_entry_stats_interval)
return 0; /* Not initialized. */
@@ -1323,31 +1388,26 @@ geoip_entry_stats_write(time_t now)
/* Discard all items in the client history that are too old. */
geoip_remove_old_clients(start_of_entry_stats_interval);
/* Generate history string .*/
str = geoip_format_entry_stats(now);
/* Write entry-stats string to disk. */
statsdir = get_datadir_fname("stats");
if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0)
if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) {
log_warn(LD_HIST, "Unable to create stats/ directory!");
goto done;
}
filename = get_datadir_fname2("stats", "entry-stats");
data = geoip_get_client_history(GEOIP_CLIENT_CONNECT);
format_iso_time(written, now);
out = start_writing_to_stdio_file(filename, OPEN_FLAGS_APPEND | O_TEXT,
0600, &open_file);
if (!out)
goto done;
if (fprintf(out, "entry-stats-end %s (%u s)\nentry-ips %s\n",
written, (unsigned) (now - start_of_entry_stats_interval),
data ? data : "") < 0)
goto done;
if (write_str_to_file(filename, str, 0) < 0)
log_warn(LD_HIST, "Unable to write entry statistics to disk!");
start_of_entry_stats_interval = now;
/* Reset measurement interval start. */
geoip_reset_entry_stats(now);
finish_writing_to_file(open_file);
open_file = NULL;
done:
if (open_file)
abort_writing_to_file(open_file);
tor_free(filename);
tor_free(statsdir);
tor_free(data);
tor_free(filename);
tor_free(str);
return start_of_entry_stats_interval + WRITE_STATS_INTERVAL;
}
+5
View File
@@ -43,12 +43,17 @@ void geoip_change_dirreq_state(uint64_t dirreq_id, dirreq_type_t type,
dirreq_state_t new_state);
void geoip_dirreq_stats_init(time_t now);
void geoip_reset_dirreq_stats(time_t now);
char *geoip_format_dirreq_stats(time_t now);
time_t geoip_dirreq_stats_write(time_t now);
void geoip_dirreq_stats_term(void);
void geoip_entry_stats_init(time_t now);
time_t geoip_entry_stats_write(time_t now);
void geoip_entry_stats_term(void);
void geoip_reset_entry_stats(time_t now);
char *geoip_format_entry_stats(time_t now);
void geoip_bridge_stats_init(time_t now);
char *geoip_format_bridge_stats(time_t now);
time_t geoip_bridge_stats_write(time_t now);
void geoip_bridge_stats_term(void);
const char *geoip_get_bridge_stats_extrainfo(time_t);
+19 -1
View File
@@ -114,6 +114,8 @@ static time_t time_to_check_for_correct_dns = 0;
static time_t time_of_last_signewnym = 0;
/** Is there a signewnym request we're currently waiting to handle? */
static int signewnym_is_pending = 0;
/** How many times have we called newnym? */
static unsigned newnym_epoch = 0;
/** Smartlist of all open connections. */
static smartlist_t *connection_array = NULL;
@@ -152,6 +154,12 @@ int can_complete_circuit=0;
* they are obsolete? */
#define TLS_HANDSHAKE_TIMEOUT (60)
/** Decides our behavior when no logs are configured/before any
* logs have been configured. For 0, we log notice to stdout as normal.
* For 1, we log warnings only. For 2, we log nothing.
*/
int quiet_level = 0;
/********* END VARIABLES ************/
/****************************************************************************
@@ -290,7 +298,7 @@ connection_unregister_events(connection_t *conn)
conn->bufev = NULL;
}
#endif
if (conn->dns_server_port) {
if (conn->type == CONN_TYPE_AP_DNS_LISTENER) {
dnsserv_close_listener(conn);
}
}
@@ -1038,9 +1046,18 @@ signewnym_impl(time_t now)
time_of_last_signewnym = now;
signewnym_is_pending = 0;
++newnym_epoch;
control_event_signal(SIGNEWNYM);
}
/** Return the number of times that signewnym has been called. */
unsigned
get_signewnym_epoch(void)
{
return newnym_epoch;
}
/** Perform regular maintenance tasks. This function gets run once per
* second by second_elapsed_callback().
*/
@@ -2137,6 +2154,7 @@ tor_init(int argc, char *argv[])
default:
add_temp_log(LOG_NOTICE);
}
quiet_level = quiet;
log(LOG_NOTICE, LD_GENERAL, "Tor v%s. This is experimental software. "
"Do not rely on it for strong anonymity. (Running on %s)",get_version(),
+1
View File
@@ -52,6 +52,7 @@ void ip_address_changed(int at_interface);
void dns_servers_relaunch_checks(void);
long get_uptime(void);
unsigned get_signewnym_epoch(void);
void handle_signals(int is_parent);
void process_signal(uintptr_t sig);
-6
View File
@@ -698,14 +698,8 @@ we_use_microdescriptors_for_circuits(const or_options_t *options)
int ret = options->UseMicrodescriptors;
if (ret == -1) {
/* UseMicrodescriptors is "auto"; we need to decide: */
#if 0
/* So we decide that we'll use microdescriptors iff we are not a server */
ret = ! server_mode(options);
#else
/* We don't use microdescs for now: not enough caches are running
* 0.2.3.1-alpha */
ret = 0;
#endif
}
return ret;
}
-7
View File
@@ -2006,13 +2006,6 @@ routers_update_status_from_consensus_networkstatus(smartlist_t *routers,
tor_memcmp(rs->identity_digest,
router->cache_info.identity_digest, DIGEST_LEN),
{
#if 0
/* We have no routerstatus for this router. Clear flags and skip it. */
if (!authdir) {
if (router->purpose == ROUTER_PURPOSE_GENERAL)
router_clear_status_flags(router);
}
#endif
}) {
/* We have a routerstatus for this router. */
const char *digest = router->cache_info.identity_digest;
+188 -11
View File
@@ -930,6 +930,11 @@ typedef struct {
typedef struct buf_t buf_t;
typedef struct socks_request_t socks_request_t;
#ifdef USE_BUFFEREVENTS
#define generic_buffer_t struct evbuffer
#else
#define generic_buffer_t buf_t
#endif
/* Values for connection_t.magic: used to make sure that downcasts (casts from
* connection_t to foo_connection_t) are safe. */
@@ -938,6 +943,7 @@ typedef struct socks_request_t socks_request_t;
#define EDGE_CONNECTION_MAGIC 0xF0374013u
#define DIR_CONNECTION_MAGIC 0x9988ffeeu
#define CONTROL_CONNECTION_MAGIC 0x8abc765du
#define LISTENER_CONNECTION_MAGIC 0x1a1ac741u
/** Description of a connection to another host or process, and associated
* data.
@@ -1043,15 +1049,31 @@ typedef struct connection_t {
/** Unique identifier for this connection on this Tor instance. */
uint64_t global_identifier;
/* XXXX023 move this field, and all the listener-only fields (just
socket_family, I think), into a new listener_connection_t subtype. */
/** Unique ID for measuring tunneled network status requests. */
uint64_t dirreq_id;
} connection_t;
typedef struct listener_connection_t {
connection_t _base;
/** If the connection is a CONN_TYPE_AP_DNS_LISTENER, this field points
* to the evdns_server_port it uses to listen to and answer connections. */
struct evdns_server_port *dns_server_port;
/** Unique ID for measuring tunneled network status requests. */
uint64_t dirreq_id;
} connection_t;
/** @name Isolation parameters
*
* For an AP listener, these fields describe how to isolate streams that
* arrive on the listener.
*
* @{
*/
/** The session group for this listener. */
int session_group;
/** One or more ISO_ flags to describe how to isolate streams. */
uint8_t isolation_flags;
/**@}*/
} listener_connection_t;
/** Stores flags and information related to the portion of a v2 Tor OR
* connection handshake that happens after the TLS handshake is finished.
@@ -1190,6 +1212,20 @@ typedef struct edge_connection_t {
/** What rendezvous service are we querying for? (AP only) */
rend_data_t *rend_data;
/* === Isolation related, AP only. === */
/** AP only: based on which factors do we isolate this stream? */
uint8_t isolation_flags;
/** AP only: what session group is this stream in? */
int session_group;
/** AP only: The newnym epoch in which we created this connection. */
unsigned nym_epoch;
/** AP only: The original requested address before we rewrote it. */
char *original_dest_address;
/* Other fields to isolate on already exist. The ClientAddr is addr. The
ClientProtocol is a combination of type and socks_request->
socks_version. SocksAuth is socks_request->username/password.
DestAddr is in socks_request->address. */
/** Number of times we've reassigned this application connection to
* a new circuit. We keep track because the timeout is longer if we've
* already retried several times. */
@@ -1232,6 +1268,21 @@ typedef struct edge_connection_t {
* NATd connection */
unsigned int is_transparent_ap:1;
/** For AP connections only: Set if this connection's target exit node
* allows optimistic data (that is, data sent on this stream before
* the exit has sent a CONNECTED cell) and we have chosen to use it.
*/
unsigned int may_use_optimistic_data : 1;
/** For AP connections only: buffer for data that we have sent
* optimistically, which we might need to re-send if we have to
* retry this connection. */
generic_buffer_t *pending_optimistic_data;
/* For AP connections only: buffer for data that we previously sent
* optimistically which we are currently re-sending as we retry this
* connection. */
generic_buffer_t *sending_optimistic_data;
/** If this is a DNSPort connection, this field holds the pending DNS
* request that we're going to try to answer. */
struct evdns_server_request *dns_server_request;
@@ -1321,6 +1372,9 @@ static edge_connection_t *TO_EDGE_CONN(connection_t *);
/** Convert a connection_t* to an control_connection_t*; assert if the cast is
* invalid. */
static control_connection_t *TO_CONTROL_CONN(connection_t *);
/** Convert a connection_t* to an listener_connection_t*; assert if the cast is
* invalid. */
static listener_connection_t *TO_LISTENER_CONN(connection_t *);
static INLINE or_connection_t *TO_OR_CONN(connection_t *c)
{
@@ -1342,6 +1396,11 @@ static INLINE control_connection_t *TO_CONTROL_CONN(connection_t *c)
tor_assert(c->magic == CONTROL_CONNECTION_MAGIC);
return DOWNCAST(control_connection_t, c);
}
static INLINE listener_connection_t *TO_LISTENER_CONN(connection_t *c)
{
tor_assert(c->magic == LISTENER_CONNECTION_MAGIC);
return DOWNCAST(listener_connection_t, c);
}
/* Conditional macros to help write code that works whether bufferevents are
disabled or not.
@@ -1667,6 +1726,9 @@ typedef struct routerstatus_t {
/** True iff this router is a version that, if it caches directory info,
* we can get microdescriptors from. */
unsigned int version_supports_microdesc_cache:1;
/** True iff this router is a version that allows DATA cells to arrive on
* a stream before it has sent a CONNECTED cell. */
unsigned int version_supports_optimistic_data:1;
unsigned int has_bandwidth:1; /**< The vote/consensus had bw info */
unsigned int has_exitsummary:1; /**< The vote/consensus had exit summaries */
@@ -2424,6 +2486,55 @@ typedef struct origin_circuit_t {
/* XXXX NM This can get re-used after 2**32 circuits. */
uint32_t global_identifier;
/** True if we have associated one stream to this circuit, thereby setting
* the isolation paramaters for this circuit. Note that this doesn't
* necessarily mean that we've <em>attached</em> any streams to the circuit:
* we may only have marked up this circuit during the launch process.
*/
unsigned int isolation_values_set : 1;
/** True iff any stream has <em>ever</em> been attached to this circuit.
*
* In a better world we could use timestamp_dirty for this, but
* timestamp_dirty is far too overloaded at the moment.
*/
unsigned int isolation_any_streams_attached : 1;
/** A bitfield of ISO_* flags for every isolation field such that this
* circuit has had streams with more than one value for that field
* attached to it. */
uint8_t isolation_flags_mixed;
/** @name Isolation parameters
*
* If any streams have been associated with this circ (isolation_values_set
* == 1), and all streams associated with the circuit have had the same
* value for some field ((isolation_flags_mixed & ISO_FOO) == 0), then these
* elements hold the value for that field.
*
* Note again that "associated" is not the same as "attached": we
* preliminarily associate streams with a circuit while the circuit is being
* launched, so that we can tell whether we need to launch more circuits.
*
* @{
*/
uint8_t client_proto_type;
uint8_t client_proto_socksver;
uint16_t dest_port;
tor_addr_t client_addr;
char *dest_address;
int session_group;
unsigned nym_epoch;
size_t socks_username_len;
uint8_t socks_password_len;
/* Note that the next two values are NOT NUL-terminated; see
socks_username_len and socks_password_len for their lengths. */
char *socks_username;
char *socks_password;
/** Global identifier for the first stream attached here; used by
* ISO_STREAM. */
uint64_t associated_isolated_stream_global_id;
/**@}*/
} origin_circuit_t;
/** An or_circuit_t holds information needed to implement a circuit at an
@@ -2542,6 +2653,60 @@ typedef enum invalid_router_usage_t {
#define MIN_CONSTRAINED_TCP_BUFFER 2048
#define MAX_CONSTRAINED_TCP_BUFFER 262144 /* 256k */
/** @name Isolation flags
Ways to isolate client streams
@{
*/
/** Isolate based on destination port */
#define ISO_DESTPORT (1u<<0)
/** Isolate based on destination address */
#define ISO_DESTADDR (1u<<1)
/** Isolate based on SOCKS authentication */
#define ISO_SOCKSAUTH (1u<<2)
/** Isolate based on client protocol choice */
#define ISO_CLIENTPROTO (1u<<3)
/** Isolate based on client address */
#define ISO_CLIENTADDR (1u<<4)
/** Isolate based on session group (always on). */
#define ISO_SESSIONGRP (1u<<5)
/** Isolate based on newnym epoch (always on). */
#define ISO_NYM_EPOCH (1u<<6)
/** Isolate all streams (Internal only). */
#define ISO_STREAM (1u<<7)
/**@}*/
/** Default isolation level for ports. */
#define ISO_DEFAULT (ISO_CLIENTADDR|ISO_SOCKSAUTH|ISO_SESSIONGRP|ISO_NYM_EPOCH)
/** Indicates that we haven't yet set a session group on a port_cfg_t. */
#define SESSION_GROUP_UNSET -1
/** Session group reserved for directory connections */
#define SESSION_GROUP_DIRCONN -2
/** Session group reserved for resolve requests launched by a controller */
#define SESSION_GROUP_CONTROL_RESOLVE -3
/** First automatically allocated session group number */
#define SESSION_GROUP_FIRST_AUTO -4
/** Configuration for a single port that we're listening on. */
typedef struct port_cfg_t {
tor_addr_t addr; /**< The actual IP to listen on, if !is_unix_addr. */
int port; /**< The configured port, or CFG_AUTO_PORT to tell Tor to pick its
* own port. */
uint8_t type; /**< One of CONN_TYPE_*_LISTENER */
unsigned is_unix_addr : 1; /**< True iff this is an AF_UNIX address. */
/* Client port types (socks, dns, trans, natd) only: */
uint8_t isolation_flags; /**< Zero or more isolation flags */
int session_group; /**< A session group, or -1 if this port is not in a
* session group. */
/* Unix sockets only: */
/** Path for an AF_UNIX address */
char unix_addr[FLEXIBLE_ARRAY_MEMBER];
} port_cfg_t;
/** A linked list of lines in a config file. */
typedef struct config_line_t {
char *key;
@@ -2637,16 +2802,17 @@ typedef struct {
char *User; /**< Name of user to run Tor as. */
char *Group; /**< Name of group to run Tor as. */
int ORPort; /**< Port to listen on for OR connections. */
int SocksPort; /**< Port to listen on for SOCKS connections. */
/** Port to listen on for transparent pf/netfilter connections. */
int TransPort;
int NATDPort; /**< Port to listen on for transparent natd connections. */
config_line_t *SocksPort; /**< Ports to listen on for SOCKS connections. */
/** Ports to listen on for transparent pf/netfilter connections. */
config_line_t *TransPort;
config_line_t *NATDPort; /**< Ports to listen on for transparent natd
* connections. */
int ControlPort; /**< Port to listen on for control connections. */
config_line_t *ControlSocket; /**< List of Unix Domain Sockets to listen on
* for control connections. */
int ControlSocketsGroupWritable; /**< Boolean: Are control sockets g+rw? */
int DirPort; /**< Port to listen on for directory connections. */
int DNSPort; /**< Port to listen on for DNS requests. */
config_line_t *DNSPort; /**< Port to listen on for DNS requests. */
int AssumeReachable; /**< Whether to publish our descriptor regardless. */
int AuthoritativeDir; /**< Boolean: is this an authoritative directory? */
int V1AuthoritativeDir; /**< Boolean: is this an authoritative directory
@@ -3108,6 +3274,15 @@ typedef struct {
/** Should that file be group-readable? */
int ControlPortFileGroupReadable;
#define MAX_MAX_CLIENT_CIRCUITS_PENDING 1024
/** Maximum number of non-open general-purpose origin circuits to allow at
* once. */
int MaxClientCircuitsPending;
/** If 1, we always send optimistic data when it's supported. If 0, we
* never use it. If -1, we do what the consensus says. */
int OptimisticData;
} or_options_t;
/** Persistent state for an onion router, as saved to disk. */
@@ -3214,6 +3389,8 @@ struct socks_request_t {
uint8_t auth_type;
/** What is this stream's goal? One of the SOCKS_COMMAND_* values */
uint8_t command;
/** Which kind of listener created this stream? */
uint8_t listener_type;
size_t replylen; /**< Length of <b>reply</b>. */
uint8_t reply[MAX_SOCKS_REPLY_LEN]; /**< Write an entry into this string if
* we want to specify our own socks reply,
@@ -3230,7 +3407,7 @@ struct socks_request_t {
unsigned int got_auth : 1; /**< Have we received any authentication data? */
/** Number of bytes in username; 0 if username is NULL */
uint8_t usernamelen;
size_t usernamelen;
/** Number of bytes in password; 0 if password is NULL */
uint8_t passwordlen;
/** The negotiated username value if any (for socks5), or the entire
+42 -2
View File
@@ -944,6 +944,12 @@ connection_edge_process_relay_cell_not_open(
break;
}
}
/* This is definitely a success, so forget about any pending data we
* had sent. */
if (conn->pending_optimistic_data) {
generic_buffer_free(conn->pending_optimistic_data);
conn->pending_optimistic_data = NULL;
}
/* handle anything that might have queued */
if (connection_edge_package_raw_inbuf(conn, 1, NULL) < 0) {
@@ -1343,6 +1349,10 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial,
char payload[CELL_PAYLOAD_SIZE];
circuit_t *circ;
unsigned domain = conn->cpath_layer ? LD_APP : LD_EXIT;
int sending_from_optimistic = 0;
const int sending_optimistically =
conn->_base.type == CONN_TYPE_AP &&
conn->_base.state != AP_CONN_STATE_OPEN;
tor_assert(conn);
@@ -1375,7 +1385,18 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial,
return 0;
}
amount_to_process = connection_get_inbuf_len(TO_CONN(conn));
sending_from_optimistic = conn->sending_optimistic_data != NULL;
if (PREDICT_UNLIKELY(sending_from_optimistic)) {
amount_to_process = generic_buffer_len(conn->sending_optimistic_data);
if (PREDICT_UNLIKELY(!amount_to_process)) {
log_warn(LD_BUG, "sending_optimistic_data was non-NULL but empty");
amount_to_process = connection_get_inbuf_len(TO_CONN(conn));
sending_from_optimistic = 0;
}
} else {
amount_to_process = connection_get_inbuf_len(TO_CONN(conn));
}
if (!amount_to_process)
return 0;
@@ -1391,11 +1412,30 @@ connection_edge_package_raw_inbuf(edge_connection_t *conn, int package_partial,
stats_n_data_bytes_packaged += length;
stats_n_data_cells_packaged += 1;
connection_fetch_from_buf(payload, length, TO_CONN(conn));
if (PREDICT_UNLIKELY(sending_from_optimistic)) {
/* XXX023 We could be more efficient here by sometimes packing
* previously-sent optimistic data in the same cell with data
* from the inbuf. */
generic_buffer_get(conn->sending_optimistic_data, payload, length);
if (!generic_buffer_len(conn->sending_optimistic_data)) {
generic_buffer_free(conn->sending_optimistic_data);
conn->sending_optimistic_data = NULL;
}
} else {
connection_fetch_from_buf(payload, length, TO_CONN(conn));
}
log_debug(domain,"(%d) Packaging %d bytes (%d waiting).", conn->_base.s,
(int)length, (int)connection_get_inbuf_len(TO_CONN(conn)));
if (sending_optimistically && !sending_from_optimistic) {
/* This is new optimistic data; remember it in case we need to detach and
retry */
if (!conn->pending_optimistic_data)
conn->pending_optimistic_data = generic_buffer_new();
generic_buffer_add(conn->pending_optimistic_data, payload, length);
}
if (connection_edge_send_command(conn, RELAY_COMMAND_DATA,
payload, length) < 0 )
/* circuit got marked for close, don't continue, don't need to mark conn */
+142 -98
View File
@@ -2364,23 +2364,41 @@ typedef struct circ_buffer_stats_t {
/** List of circ_buffer_stats_t. */
static smartlist_t *circuits_for_buffer_stats = NULL;
/** Remember cell statistics <b>mean_num_cells_in_queue</b>,
* <b>mean_time_cells_in_queue</b>, and <b>processed_cells</b> of a
* circuit. */
void
rep_hist_add_buffer_stats(double mean_num_cells_in_queue,
double mean_time_cells_in_queue, uint32_t processed_cells)
{
circ_buffer_stats_t *stat;
if (!start_of_buffer_stats_interval)
return; /* Not initialized. */
stat = tor_malloc_zero(sizeof(circ_buffer_stats_t));
stat->mean_num_cells_in_queue = mean_num_cells_in_queue;
stat->mean_time_cells_in_queue = mean_time_cells_in_queue;
stat->processed_cells = processed_cells;
if (!circuits_for_buffer_stats)
circuits_for_buffer_stats = smartlist_create();
smartlist_add(circuits_for_buffer_stats, stat);
}
/** Remember cell statistics for circuit <b>circ</b> at time
* <b>end_of_interval</b> and reset cell counters in case the circuit
* remains open in the next measurement interval. */
void
rep_hist_buffer_stats_add_circ(circuit_t *circ, time_t end_of_interval)
{
circ_buffer_stats_t *stat;
time_t start_of_interval;
int interval_length;
or_circuit_t *orcirc;
double mean_num_cells_in_queue, mean_time_cells_in_queue;
uint32_t processed_cells;
if (CIRCUIT_IS_ORIGIN(circ))
return;
orcirc = TO_OR_CIRCUIT(circ);
if (!orcirc->processed_cells)
return;
if (!circuits_for_buffer_stats)
circuits_for_buffer_stats = smartlist_create();
start_of_interval = (circ->timestamp_created.tv_sec >
start_of_buffer_stats_interval) ?
circ->timestamp_created.tv_sec :
@@ -2388,17 +2406,18 @@ rep_hist_buffer_stats_add_circ(circuit_t *circ, time_t end_of_interval)
interval_length = (int) (end_of_interval - start_of_interval);
if (interval_length <= 0)
return;
stat = tor_malloc_zero(sizeof(circ_buffer_stats_t));
stat->processed_cells = orcirc->processed_cells;
processed_cells = orcirc->processed_cells;
/* 1000.0 for s -> ms; 2.0 because of app-ward and exit-ward queues */
stat->mean_num_cells_in_queue = (double) orcirc->total_cell_waiting_time /
mean_num_cells_in_queue = (double) orcirc->total_cell_waiting_time /
(double) interval_length / 1000.0 / 2.0;
stat->mean_time_cells_in_queue =
mean_time_cells_in_queue =
(double) orcirc->total_cell_waiting_time /
(double) orcirc->processed_cells;
smartlist_add(circuits_for_buffer_stats, stat);
orcirc->total_cell_waiting_time = 0;
orcirc->processed_cells = 0;
rep_hist_add_buffer_stats(mean_num_cells_in_queue,
mean_time_cells_in_queue,
processed_cells);
}
/** Sorting helper: return -1, 1, or 0 based on comparison of two
@@ -2420,135 +2439,160 @@ _buffer_stats_compare_entries(const void **_a, const void **_b)
void
rep_hist_buffer_stats_term(void)
{
start_of_buffer_stats_interval = 0;
rep_hist_reset_buffer_stats(0);
}
/** Clear history of circuit statistics and set the measurement interval
* start to <b>now</b>. */
void
rep_hist_reset_buffer_stats(time_t now)
{
if (!circuits_for_buffer_stats)
circuits_for_buffer_stats = smartlist_create();
SMARTLIST_FOREACH(circuits_for_buffer_stats, circ_buffer_stats_t *,
stat, tor_free(stat));
smartlist_clear(circuits_for_buffer_stats);
start_of_buffer_stats_interval = now;
}
/** Write buffer statistics to $DATADIR/stats/buffer-stats and return when
* we would next want to write exit stats. */
time_t
rep_hist_buffer_stats_write(time_t now)
/** Return a newly allocated string containing the buffer statistics until
* <b>now</b>, or NULL if we're not collecting buffer stats. */
char *
rep_hist_format_buffer_stats(time_t now)
{
char *statsdir = NULL, *filename = NULL;
char written[ISO_TIME_LEN+1];
open_file_t *open_file = NULL;
FILE *out;
#define SHARES 10
int processed_cells[SHARES], circs_in_share[SHARES],
number_of_circuits, i;
double queued_cells[SHARES], time_in_queue[SHARES];
smartlist_t *str_build = NULL;
char *str = NULL, *buf = NULL;
circuit_t *circ;
char *buf = NULL;
smartlist_t *processed_cells_strings, *queued_cells_strings,
*time_in_queue_strings;
char *processed_cells_string, *queued_cells_string,
*time_in_queue_string;
char t[ISO_TIME_LEN+1];
char *result;
if (!start_of_buffer_stats_interval)
return 0; /* Not initialized. */
if (start_of_buffer_stats_interval + WRITE_STATS_INTERVAL > now)
goto done; /* Not ready to write */
return NULL; /* Not initialized. */
str_build = smartlist_create();
/* add current circuits to stats */
for (circ = _circuit_get_global_list(); circ; circ = circ->next)
rep_hist_buffer_stats_add_circ(circ, now);
/* calculate deciles */
/* Calculate deciles if we saw at least one circuit. */
memset(processed_cells, 0, SHARES * sizeof(int));
memset(circs_in_share, 0, SHARES * sizeof(int));
memset(queued_cells, 0, SHARES * sizeof(double));
memset(time_in_queue, 0, SHARES * sizeof(double));
if (!circuits_for_buffer_stats)
circuits_for_buffer_stats = smartlist_create();
smartlist_sort(circuits_for_buffer_stats,
_buffer_stats_compare_entries);
number_of_circuits = smartlist_len(circuits_for_buffer_stats);
if (number_of_circuits < 1) {
log_info(LD_HIST, "Attempt to write cell statistics to disk failed. "
"We haven't seen a single circuit to report about.");
goto done;
if (number_of_circuits > 0) {
smartlist_sort(circuits_for_buffer_stats,
_buffer_stats_compare_entries);
i = 0;
SMARTLIST_FOREACH_BEGIN(circuits_for_buffer_stats,
circ_buffer_stats_t *, stat)
{
int share = i++ * SHARES / number_of_circuits;
processed_cells[share] += stat->processed_cells;
queued_cells[share] += stat->mean_num_cells_in_queue;
time_in_queue[share] += stat->mean_time_cells_in_queue;
circs_in_share[share]++;
}
SMARTLIST_FOREACH_END(stat);
}
i = 0;
SMARTLIST_FOREACH_BEGIN(circuits_for_buffer_stats,
circ_buffer_stats_t *, stat)
{
int share = i++ * SHARES / number_of_circuits;
processed_cells[share] += stat->processed_cells;
queued_cells[share] += stat->mean_num_cells_in_queue;
time_in_queue[share] += stat->mean_time_cells_in_queue;
circs_in_share[share]++;
}
SMARTLIST_FOREACH_END(stat);
/* clear buffer stats history */
SMARTLIST_FOREACH(circuits_for_buffer_stats, circ_buffer_stats_t *,
stat, tor_free(stat));
smartlist_clear(circuits_for_buffer_stats);
/* write to file */
statsdir = get_datadir_fname("stats");
if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0)
goto done;
filename = get_datadir_fname2("stats", "buffer-stats");
out = start_writing_to_stdio_file(filename, OPEN_FLAGS_APPEND | O_TEXT,
0600, &open_file);
if (!out)
goto done;
format_iso_time(written, now);
if (fprintf(out, "cell-stats-end %s (%d s)\n", written,
(unsigned) (now - start_of_buffer_stats_interval)) < 0)
goto done;
/* Write deciles to strings. */
processed_cells_strings = smartlist_create();
queued_cells_strings = smartlist_create();
time_in_queue_strings = smartlist_create();
for (i = 0; i < SHARES; i++) {
tor_asprintf(&buf,"%d", !circs_in_share[i] ? 0 :
processed_cells[i] / circs_in_share[i]);
smartlist_add(str_build, buf);
smartlist_add(processed_cells_strings, buf);
}
str = smartlist_join_strings(str_build, ",", 0, NULL);
if (fprintf(out, "cell-processed-cells %s\n", str) < 0)
goto done;
tor_free(str);
SMARTLIST_FOREACH(str_build, char *, c, tor_free(c));
smartlist_clear(str_build);
for (i = 0; i < SHARES; i++) {
tor_asprintf(&buf, "%.2f", circs_in_share[i] == 0 ? 0.0 :
queued_cells[i] / (double) circs_in_share[i]);
smartlist_add(str_build, buf);
smartlist_add(queued_cells_strings, buf);
}
str = smartlist_join_strings(str_build, ",", 0, NULL);
if (fprintf(out, "cell-queued-cells %s\n", str) < 0)
goto done;
tor_free(str);
SMARTLIST_FOREACH(str_build, char *, c, tor_free(c));
smartlist_clear(str_build);
for (i = 0; i < SHARES; i++) {
tor_asprintf(&buf, "%.0f", circs_in_share[i] == 0 ? 0.0 :
time_in_queue[i] / (double) circs_in_share[i]);
smartlist_add(str_build, buf);
smartlist_add(time_in_queue_strings, buf);
}
str = smartlist_join_strings(str_build, ",", 0, NULL);
if (fprintf(out, "cell-time-in-queue %s\n", str) < 0)
/* Join all observations in single strings. */
processed_cells_string = smartlist_join_strings(processed_cells_strings,
",", 0, NULL);
queued_cells_string = smartlist_join_strings(queued_cells_strings,
",", 0, NULL);
time_in_queue_string = smartlist_join_strings(time_in_queue_strings,
",", 0, NULL);
SMARTLIST_FOREACH(processed_cells_strings, char *, cp, tor_free(cp));
SMARTLIST_FOREACH(queued_cells_strings, char *, cp, tor_free(cp));
SMARTLIST_FOREACH(time_in_queue_strings, char *, cp, tor_free(cp));
smartlist_free(processed_cells_strings);
smartlist_free(queued_cells_strings);
smartlist_free(time_in_queue_strings);
/* Put everything together. */
format_iso_time(t, now);
tor_asprintf(&result, "cell-stats-end %s (%d s)\n"
"cell-processed-cells %s\n"
"cell-queued-cells %s\n"
"cell-time-in-queue %s\n"
"cell-circuits-per-decile %d\n",
t, (unsigned) (now - start_of_buffer_stats_interval),
processed_cells_string,
queued_cells_string,
time_in_queue_string,
(number_of_circuits + SHARES - 1) / SHARES);
tor_free(processed_cells_string);
tor_free(queued_cells_string);
tor_free(time_in_queue_string);
return result;
#undef SHARES
}
/** If 24 hours have passed since the beginning of the current buffer
* stats period, write buffer stats to $DATADIR/stats/buffer-stats
* (possibly overwriting an existing file) and reset counters. Return
* when we would next want to write buffer stats or 0 if we never want to
* write. */
time_t
rep_hist_buffer_stats_write(time_t now)
{
circuit_t *circ;
char *statsdir = NULL, *filename = NULL, *str = NULL;
if (!start_of_buffer_stats_interval)
return 0; /* Not initialized. */
if (start_of_buffer_stats_interval + WRITE_STATS_INTERVAL > now)
goto done; /* Not ready to write */
/* Add open circuits to the history. */
for (circ = _circuit_get_global_list(); circ; circ = circ->next) {
rep_hist_buffer_stats_add_circ(circ, now);
}
/* Generate history string. */
str = rep_hist_format_buffer_stats(now);
/* Reset both buffer history and counters of open circuits. */
rep_hist_reset_buffer_stats(now);
/* Try to write to disk. */
statsdir = get_datadir_fname("stats");
if (check_private_dir(statsdir, CPD_CREATE, get_options()->User) < 0) {
log_warn(LD_HIST, "Unable to create stats/ directory!");
goto done;
tor_free(str);
SMARTLIST_FOREACH(str_build, char *, c, tor_free(c));
smartlist_free(str_build);
str_build = NULL;
if (fprintf(out, "cell-circuits-per-decile %d\n",
(number_of_circuits + SHARES - 1) / SHARES) < 0)
goto done;
finish_writing_to_file(open_file);
open_file = NULL;
start_of_buffer_stats_interval = now;
}
filename = get_datadir_fname2("stats", "buffer-stats");
if (write_str_to_file(filename, str, 0) < 0)
log_warn(LD_HIST, "Unable to write buffer stats to disk!");
done:
if (open_file)
abort_writing_to_file(open_file);
tor_free(str);
tor_free(filename);
tor_free(statsdir);
if (str_build) {
SMARTLIST_FOREACH(str_build, char *, c, tor_free(c));
smartlist_free(str_build);
}
tor_free(str);
#undef SHARES
return start_of_buffer_stats_interval + WRITE_STATS_INTERVAL;
}
+4
View File
@@ -77,6 +77,10 @@ void rep_hist_buffer_stats_add_circ(circuit_t *circ,
time_t end_of_interval);
time_t rep_hist_buffer_stats_write(time_t now);
void rep_hist_buffer_stats_term(void);
void rep_hist_add_buffer_stats(double mean_num_cells_in_queue,
double mean_time_cells_in_queue, uint32_t processed_cells);
char *rep_hist_format_buffer_stats(time_t now);
void rep_hist_reset_buffer_stats(time_t now);
void rep_hist_conn_stats_init(time_t now);
void rep_hist_note_or_conn_bytes(uint64_t conn_id, size_t num_read,
+3 -5
View File
@@ -1116,14 +1116,12 @@ set_server_advertised(int s)
server_is_advertised = s;
}
/** Return true iff we are trying to be a socks proxy. */
/** Return true iff we are trying to proxy client connections. */
int
proxy_mode(const or_options_t *options)
{
return (options->SocksPort != 0 ||
options->TransPort != 0 ||
options->NATDPort != 0 ||
options->DNSPort != 0);
(void)options;
return smartlist_len(get_configured_client_ports()) > 0;
}
/** Decide if we're a publishable server. We are a publishable server if:
+3
View File
@@ -2092,6 +2092,7 @@ routerstatus_parse_entry_from_string(memarea_t *area,
rs->version_supports_extrainfo_upload = 1;
rs->version_supports_conditional_consensus = 1;
rs->version_supports_microdesc_cache = 1;
rs->version_supports_optimistic_data = 1;
} else {
rs->version_supports_begindir =
tor_version_as_new_as(tok->args[0], "0.2.0.1-alpha");
@@ -2109,6 +2110,8 @@ routerstatus_parse_entry_from_string(memarea_t *area,
*/
rs->version_supports_microdesc_cache =
tor_version_as_new_as(tok->args[0], "0.2.3.0-alpha");
rs->version_supports_optimistic_data =
tor_version_as_new_as(tok->args[0], "0.2.3.1-alpha");
}
if (vote_rs) {
vote_rs->version = tor_strdup(tok->args[0]);
+295 -1
View File
@@ -569,6 +569,71 @@ test_socks_5_auth_before_negotiation(void *ptr)
;
}
static void
test_buffer_copy(void *arg)
{
generic_buffer_t *buf=NULL, *buf2=NULL;
const char *s;
size_t len;
char b[256];
int i;
(void)arg;
buf = generic_buffer_new();
tt_assert(buf);
/* Copy an empty buffer. */
tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf));
tt_assert(buf2);
tt_int_op(0, ==, generic_buffer_len(buf2));
/* Now try with a short buffer. */
s = "And now comes an act of enormous enormance!";
len = strlen(s);
generic_buffer_add(buf, s, len);
tt_int_op(len, ==, generic_buffer_len(buf));
/* Add junk to buf2 so we can test replacing.*/
generic_buffer_add(buf2, "BLARG", 5);
tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf));
tt_int_op(len, ==, generic_buffer_len(buf2));
generic_buffer_get(buf2, b, len);
test_mem_op(b, ==, s, len);
/* Now free buf2 and retry so we can test allocating */
generic_buffer_free(buf2);
buf2 = NULL;
tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf));
tt_int_op(len, ==, generic_buffer_len(buf2));
generic_buffer_get(buf2, b, len);
test_mem_op(b, ==, s, len);
/* Clear buf for next test */
generic_buffer_get(buf, b, len);
tt_int_op(generic_buffer_len(buf),==,0);
/* Okay, now let's try a bigger buffer. */
s = "Quis autem vel eum iure reprehenderit qui in ea voluptate velit "
"esse quam nihil molestiae consequatur, vel illum qui dolorem eum "
"fugiat quo voluptas nulla pariatur?";
len = strlen(s);
for (i = 0; i < 256; ++i) {
b[0]=i;
generic_buffer_add(buf, b, 1);
generic_buffer_add(buf, s, len);
}
tt_int_op(0, ==, generic_buffer_set_to_copy(&buf2, buf));
tt_int_op(generic_buffer_len(buf2), ==, generic_buffer_len(buf));
for (i = 0; i < 256; ++i) {
generic_buffer_get(buf2, b, len+1);
tt_int_op((unsigned char)b[0],==,i);
test_mem_op(b+1, ==, s, len);
}
done:
if (buf)
generic_buffer_free(buf);
if (buf2)
generic_buffer_free(buf2);
}
/** Run unit tests for buffers.c */
static void
test_buffers(void)
@@ -1416,8 +1481,73 @@ static void
test_geoip(void)
{
int i, j;
time_t now = time(NULL);
time_t now = 1281533250; /* 2010-08-11 13:27:30 UTC */
char *s = NULL;
const char *bridge_stats_1 =
"bridge-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"bridge-ips zz=24,xy=8\n",
*dirreq_stats_1 =
"dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"dirreq-v3-ips ab=8\n"
"dirreq-v2-ips \n"
"dirreq-v3-reqs ab=8\n"
"dirreq-v2-reqs \n"
"dirreq-v3-resp ok=0,not-enough-sigs=0,unavailable=0,not-found=0,"
"not-modified=0,busy=0\n"
"dirreq-v2-resp ok=0,unavailable=0,not-found=0,not-modified=0,"
"busy=0\n"
"dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
"dirreq-v2-direct-dl complete=0,timeout=0,running=0\n"
"dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n"
"dirreq-v2-tunneled-dl complete=0,timeout=0,running=0\n",
*dirreq_stats_2 =
"dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"dirreq-v3-ips \n"
"dirreq-v2-ips \n"
"dirreq-v3-reqs \n"
"dirreq-v2-reqs \n"
"dirreq-v3-resp ok=0,not-enough-sigs=0,unavailable=0,not-found=0,"
"not-modified=0,busy=0\n"
"dirreq-v2-resp ok=0,unavailable=0,not-found=0,not-modified=0,"
"busy=0\n"
"dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
"dirreq-v2-direct-dl complete=0,timeout=0,running=0\n"
"dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n"
"dirreq-v2-tunneled-dl complete=0,timeout=0,running=0\n",
*dirreq_stats_3 =
"dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"dirreq-v3-ips \n"
"dirreq-v2-ips \n"
"dirreq-v3-reqs \n"
"dirreq-v2-reqs \n"
"dirreq-v3-resp ok=8,not-enough-sigs=0,unavailable=0,not-found=0,"
"not-modified=0,busy=0\n"
"dirreq-v2-resp ok=0,unavailable=0,not-found=0,not-modified=0,"
"busy=0\n"
"dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
"dirreq-v2-direct-dl complete=0,timeout=0,running=0\n"
"dirreq-v3-tunneled-dl complete=0,timeout=0,running=0\n"
"dirreq-v2-tunneled-dl complete=0,timeout=0,running=0\n",
*dirreq_stats_4 =
"dirreq-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"dirreq-v3-ips \n"
"dirreq-v2-ips \n"
"dirreq-v3-reqs \n"
"dirreq-v2-reqs \n"
"dirreq-v3-resp ok=8,not-enough-sigs=0,unavailable=0,not-found=0,"
"not-modified=0,busy=0\n"
"dirreq-v2-resp ok=0,unavailable=0,not-found=0,not-modified=0,"
"busy=0\n"
"dirreq-v3-direct-dl complete=0,timeout=0,running=0\n"
"dirreq-v2-direct-dl complete=0,timeout=0,running=0\n"
"dirreq-v3-tunneled-dl complete=0,timeout=0,running=4\n"
"dirreq-v2-tunneled-dl complete=0,timeout=0,running=0\n",
*entry_stats_1 =
"entry-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"entry-ips ab=8\n",
*entry_stats_2 =
"entry-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"entry-ips \n";
/* Populate the DB a bit. Add these in order, since we can't do the final
* 'sort' step. These aren't very good IP addresses, but they're perfectly
@@ -1467,6 +1597,114 @@ test_geoip(void)
test_assert(s);
test_streq("zz=24,xy=8", s);
/* Start testing bridge statistics by making sure that we don't output
* bridge stats without initializing them. */
s = geoip_format_bridge_stats(now + 86400);
test_assert(!s);
/* Initialize stats and generate the bridge-stats history string out of
* the connecting clients added above. */
geoip_bridge_stats_init(now);
s = geoip_format_bridge_stats(now + 86400);
test_streq(bridge_stats_1, s);
tor_free(s);
/* Stop collecting bridge stats and make sure we don't write a history
* string anymore. */
geoip_bridge_stats_term();
s = geoip_format_bridge_stats(now + 86400);
test_assert(!s);
/* Stop being a bridge and start being a directory mirror that gathers
* directory request statistics. */
geoip_bridge_stats_term();
get_options_mutable()->BridgeRelay = 0;
get_options_mutable()->BridgeRecordUsageByCountry = 0;
get_options_mutable()->DirReqStatistics = 1;
/* Start testing dirreq statistics by making sure that we don't collect
* dirreq stats without initializing them. */
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, 100, now);
s = geoip_format_dirreq_stats(now + 86400);
test_assert(!s);
/* Initialize stats, note one connecting client, and generate the
* dirreq-stats history string. */
geoip_dirreq_stats_init(now);
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, 100, now);
s = geoip_format_dirreq_stats(now + 86400);
test_streq(dirreq_stats_1, s);
tor_free(s);
/* Stop collecting stats, add another connecting client, and ensure we
* don't generate a history string. */
geoip_dirreq_stats_term();
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, 101, now);
s = geoip_format_dirreq_stats(now + 86400);
test_assert(!s);
/* Re-start stats, add a connecting client, reset stats, and make sure
* that we get an all empty history string. */
geoip_dirreq_stats_init(now);
geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, 100, now);
geoip_reset_dirreq_stats(now);
s = geoip_format_dirreq_stats(now + 86400);
test_streq(dirreq_stats_2, s);
tor_free(s);
/* Note a successful network status response and make sure that it
* appears in the history string. */
geoip_note_ns_response(GEOIP_CLIENT_NETWORKSTATUS, GEOIP_SUCCESS);
s = geoip_format_dirreq_stats(now + 86400);
test_streq(dirreq_stats_3, s);
tor_free(s);
/* Start a tunneled directory request. */
geoip_start_dirreq((uint64_t) 1, 1024, GEOIP_CLIENT_NETWORKSTATUS,
DIRREQ_TUNNELED);
s = geoip_format_dirreq_stats(now + 86400);
test_streq(dirreq_stats_4, s);
/* Stop collecting directory request statistics and start gathering
* entry stats. */
geoip_dirreq_stats_term();
get_options_mutable()->DirReqStatistics = 0;
get_options_mutable()->EntryStatistics = 1;
/* Start testing entry statistics by making sure that we don't collect
* anything without initializing entry stats. */
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, 100, now);
s = geoip_format_entry_stats(now + 86400);
test_assert(!s);
/* Initialize stats, note one connecting client, and generate the
* entry-stats history string. */
geoip_entry_stats_init(now);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, 100, now);
s = geoip_format_entry_stats(now + 86400);
test_streq(entry_stats_1, s);
tor_free(s);
/* Stop collecting stats, add another connecting client, and ensure we
* don't generate a history string. */
geoip_entry_stats_term();
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, 101, now);
s = geoip_format_entry_stats(now + 86400);
test_assert(!s);
/* Re-start stats, add a connecting client, reset stats, and make sure
* that we get an all empty history string. */
geoip_entry_stats_init(now);
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, 100, now);
geoip_reset_entry_stats(now);
s = geoip_format_entry_stats(now + 86400);
test_streq(entry_stats_2, s);
tor_free(s);
/* Stop collecting entry statistics. */
geoip_entry_stats_term();
get_options_mutable()->EntryStatistics = 0;
done:
tor_free(s);
}
@@ -1570,6 +1808,61 @@ test_stats(void)
rep_hist_reset_conn_stats(now);
s = rep_hist_format_conn_stats(now + 86400);
test_streq("conn-bi-direct 2010-08-12 13:27:30 (86400 s) 0,0,0,0\n", s);
tor_free(s);
/* Continue with testing buffer statistics; we shouldn't collect buffer
* stats without initializing them. */
rep_hist_add_buffer_stats(2.0, 2.0, 20);
s = rep_hist_format_buffer_stats(now + 86400);
test_assert(!s);
/* Initialize stats, add statistics for a single circuit, and generate
* the history string. */
rep_hist_buffer_stats_init(now);
rep_hist_add_buffer_stats(2.0, 2.0, 20);
s = rep_hist_format_buffer_stats(now + 86400);
test_streq("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"cell-processed-cells 20,0,0,0,0,0,0,0,0,0\n"
"cell-queued-cells 2.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,"
"0.00,0.00\n"
"cell-time-in-queue 2,0,0,0,0,0,0,0,0,0\n"
"cell-circuits-per-decile 1\n", s);
tor_free(s);
/* Add nineteen more circuit statistics to the one that's already in the
* history to see that the math works correctly. */
for (i = 21; i < 30; i++)
rep_hist_add_buffer_stats(2.0, 2.0, i);
for (i = 20; i < 30; i++)
rep_hist_add_buffer_stats(3.5, 3.5, i);
s = rep_hist_format_buffer_stats(now + 86400);
test_streq("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"cell-processed-cells 29,28,27,26,25,24,23,22,21,20\n"
"cell-queued-cells 2.75,2.75,2.75,2.75,2.75,2.75,2.75,2.75,"
"2.75,2.75\n"
"cell-time-in-queue 3,3,3,3,3,3,3,3,3,3\n"
"cell-circuits-per-decile 2\n", s);
tor_free(s);
/* Stop collecting stats, add statistics for one circuit, and ensure we
* don't generate a history string. */
rep_hist_buffer_stats_term();
rep_hist_add_buffer_stats(2.0, 2.0, 20);
s = rep_hist_format_buffer_stats(now + 86400);
test_assert(!s);
/* Re-start stats, add statistics for one circuit, reset stats, and make
* sure that the history has all zeros. */
rep_hist_buffer_stats_init(now);
rep_hist_add_buffer_stats(2.0, 2.0, 20);
rep_hist_reset_buffer_stats(now);
s = rep_hist_format_buffer_stats(now + 86400);
test_streq("cell-stats-end 2010-08-12 13:27:30 (86400 s)\n"
"cell-processed-cells 0,0,0,0,0,0,0,0,0,0\n"
"cell-queued-cells 0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,"
"0.00,0.00\n"
"cell-time-in-queue 0,0,0,0,0,0,0,0,0,0\n"
"cell-circuits-per-decile 0\n", s);
done:
tor_free(s);
@@ -1612,6 +1905,7 @@ const struct testcase_setup_t legacy_setup = {
static struct testcase_t test_array[] = {
ENT(buffers),
{ "buffer_copy", test_buffer_copy, 0, NULL, NULL },
ENT(onion_handshake),
ENT(circuit_timeout),
ENT(policies),
+1 -1
View File
@@ -34,5 +34,5 @@ miniupnpc_cppflags =
endif
tor_fw_helper_LDFLAGS = $(nat_pmp_ldflags) $(miniupnpc_ldflags)
tor_fw_helper_LDADD = $(nat_pmp_ldadd) $(miniupnpc_ldadd) ../../common/libor.a @TOR_LIB_WS32@
tor_fw_helper_LDADD = ../../common/libor.a $(nat_pmp_ldadd) $(miniupnpc_ldadd) @TOR_LIB_WS32@
tor_fw_helper_CPPFLAGS = $(nat_pmp_cppflags) $(miniupnpc_cppflags)
+10
View File
@@ -122,6 +122,7 @@
/* Define to 1 if you have the <sys/socket.h> header file. */
#undef HAVE_SYS_SOCKET_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H
@@ -234,3 +235,12 @@
/* Version number of package */
#define VERSION "0.2.3.2-alpha-dev"
#define HAVE_STRUCT_SOCKADDR_IN6
#define HAVE_STRUCT_IN6_ADDR
#define RSHIFT_DOES_SIGN_EXTEND
#define FLEXIBLE_ARRAY_MEMBER 0
#define HAVE_EVENT2_EVENT_H
#define SHARE_DATADIR ""