aboutsummaryrefslogtreecommitdiff
path: root/src/or
diff options
context:
space:
mode:
Diffstat (limited to 'src/or')
-rw-r--r--src/or/addressmap.c2
-rw-r--r--src/or/addressmap.h6
-rw-r--r--src/or/buffers.c61
-rw-r--r--src/or/buffers.h12
-rw-r--r--src/or/channel.c12
-rw-r--r--src/or/channel.h2
-rw-r--r--src/or/channeltls.c32
-rw-r--r--src/or/circuitlist.c15
-rw-r--r--src/or/circuitlist.h7
-rw-r--r--src/or/circuitmux.c13
-rw-r--r--src/or/circuitmux.h9
-rw-r--r--src/or/circuitstats.c21
-rw-r--r--src/or/circuitstats.h21
-rw-r--r--src/or/config.c231
-rw-r--r--src/or/config.h24
-rw-r--r--src/or/confparse.c16
-rw-r--r--src/or/confparse.h2
-rw-r--r--src/or/connection.c91
-rw-r--r--src/or/connection.h10
-rw-r--r--src/or/connection_edge.c4
-rw-r--r--src/or/connection_edge.h6
-rw-r--r--src/or/connection_or.c82
-rw-r--r--src/or/connection_or.h3
-rw-r--r--src/or/control.c59
-rw-r--r--src/or/control.h10
-rw-r--r--src/or/directory.c4
-rw-r--r--src/or/dirserv.c18
-rw-r--r--src/or/dirserv.h23
-rw-r--r--src/or/dirvote.c18
-rw-r--r--src/or/dirvote.h6
-rw-r--r--src/or/dns.c8
-rw-r--r--src/or/entrynodes.c17
-rw-r--r--src/or/ext_orport.c648
-rw-r--r--src/or/ext_orport.h42
-rw-r--r--src/or/geoip.c174
-rw-r--r--src/or/geoip.h12
-rw-r--r--src/or/hibernate.c2
-rw-r--r--src/or/hibernate.h2
-rw-r--r--src/or/include.am32
-rw-r--r--src/or/main.c65
-rw-r--r--src/or/main.h15
-rw-r--r--src/or/ntmain.c1
-rw-r--r--src/or/or.h77
-rw-r--r--src/or/relay.c44
-rw-r--r--src/or/relay.h8
-rw-r--r--src/or/rendservice.c12
-rw-r--r--src/or/rendservice.h2
-rw-r--r--src/or/replaycache.c27
-rw-r--r--src/or/replaycache.h10
-rw-r--r--src/or/router.c2
-rw-r--r--src/or/router.h4
-rw-r--r--src/or/routerlist.c4
-rw-r--r--src/or/routerlist.h9
-rw-r--r--src/or/statefile.c7
-rw-r--r--src/or/statefile.h6
-rw-r--r--src/or/transports.c165
-rw-r--r--src/or/transports.h22
57 files changed, 1909 insertions, 328 deletions
diff --git a/src/or/addressmap.c b/src/or/addressmap.c
index 79e4b7c5e..9bc79bd84 100644
--- a/src/or/addressmap.c
+++ b/src/or/addressmap.c
@@ -798,7 +798,7 @@ address_is_in_virtual_range(const char *address)
/** Return a random address conforming to the virtual address configuration
* in <b>conf</b>.
*/
-/* private */ void
+STATIC void
get_random_virtual_addr(const virtual_addr_conf_t *conf, tor_addr_t *addr_out)
{
uint8_t tmp[4];
diff --git a/src/or/addressmap.h b/src/or/addressmap.h
index 40210ee99..417832b31 100644
--- a/src/or/addressmap.h
+++ b/src/or/addressmap.h
@@ -7,6 +7,8 @@
#ifndef TOR_ADDRESSMAP_H
#define TOR_ADDRESSMAP_H
+#include "testsupport.h"
+
void addressmap_init(void);
void addressmap_clear_excluded_trackexithosts(const or_options_t *options);
void addressmap_clear_invalid_automaps(const or_options_t *options);
@@ -52,8 +54,8 @@ typedef struct virtual_addr_conf_t {
maskbits_t bits;
} virtual_addr_conf_t;
-void get_random_virtual_addr(const virtual_addr_conf_t *conf,
- tor_addr_t *addr_out);
+STATIC void get_random_virtual_addr(const virtual_addr_conf_t *conf,
+ tor_addr_t *addr_out);
#endif
#endif
diff --git a/src/or/buffers.c b/src/or/buffers.c
index c4c847ec8..50016d3a8 100644
--- a/src/or/buffers.c
+++ b/src/or/buffers.c
@@ -19,6 +19,7 @@
#include "connection_or.h"
#include "control.h"
#include "reasons.h"
+#include "ext_orport.h"
#include "../common/util.h"
#include "../common/torlog.h"
#ifdef HAVE_UNISTD_H
@@ -1294,7 +1295,7 @@ buf_matches_at_pos(const buf_pos_t *pos, const char *s, size_t n)
/** Return the first position in <b>buf</b> at which the <b>n</b>-character
* string <b>s</b> occurs, or -1 if it does not occur. */
-/*private*/ int
+STATIC int
buf_find_string_offset(const buf_t *buf, const char *s, size_t n)
{
buf_pos_t pos;
@@ -1702,6 +1703,64 @@ fetch_from_evbuffer_socks(struct evbuffer *buf, socks_request_t *req,
}
#endif
+/** The size of the header of an Extended ORPort message: 2 bytes for
+ * COMMAND, 2 bytes for BODYLEN */
+#define EXT_OR_CMD_HEADER_SIZE 4
+
+/** Read <b>buf</b>, which should contain an Extended ORPort message
+ * from a transport proxy. If well-formed, create and populate
+ * <b>out</b> with the Extended ORport message. Return 0 if the
+ * buffer was incomplete, 1 if it was well-formed and -1 if we
+ * encountered an error while parsing it. */
+int
+fetch_ext_or_command_from_buf(buf_t *buf, ext_or_cmd_t **out)
+{
+ char hdr[EXT_OR_CMD_HEADER_SIZE];
+ uint16_t len;
+
+ check();
+ if (buf->datalen < EXT_OR_CMD_HEADER_SIZE)
+ return 0;
+ peek_from_buf(hdr, sizeof(hdr), buf);
+ len = ntohs(get_uint16(hdr+2));
+ if (buf->datalen < (unsigned)len + EXT_OR_CMD_HEADER_SIZE)
+ return 0;
+ *out = ext_or_cmd_new(len);
+ (*out)->cmd = ntohs(get_uint16(hdr));
+ (*out)->len = len;
+ buf_remove_from_front(buf, EXT_OR_CMD_HEADER_SIZE);
+ fetch_from_buf((*out)->body, len, buf);
+ return 1;
+}
+
+#ifdef USE_BUFFEREVENTS
+/** Read <b>buf</b>, which should contain an Extended ORPort message
+ * from a transport proxy. If well-formed, create and populate
+ * <b>out</b> with the Extended ORport message. Return 0 if the
+ * buffer was incomplete, 1 if it was well-formed and -1 if we
+ * encountered an error while parsing it. */
+int
+fetch_ext_or_command_from_evbuffer(struct evbuffer *buf, ext_or_cmd_t **out)
+{
+ char hdr[EXT_OR_CMD_HEADER_SIZE];
+ uint16_t len;
+ size_t buf_len = evbuffer_get_length(buf);
+
+ if (buf_len < EXT_OR_CMD_HEADER_SIZE)
+ return 0;
+ evbuffer_copyout(buf, hdr, EXT_OR_CMD_HEADER_SIZE);
+ len = ntohs(get_uint16(hdr+2));
+ if (buf_len < (unsigned)len + EXT_OR_CMD_HEADER_SIZE)
+ return 0;
+ *out = ext_or_cmd_new(len);
+ (*out)->cmd = ntohs(get_uint16(hdr));
+ (*out)->len = len;
+ evbuffer_drain(buf, EXT_OR_CMD_HEADER_SIZE);
+ evbuffer_remove(buf, (*out)->body, len);
+ return 1;
+}
+#endif
+
/** Implementation helper to implement fetch_from_*_socks. Instead of looking
* at a buffer's contents, we look at the <b>datalen</b> bytes of data in
* <b>data</b>. Instead of removing data from the buffer, we set
diff --git a/src/or/buffers.h b/src/or/buffers.h
index c947f0ba9..48b118520 100644
--- a/src/or/buffers.h
+++ b/src/or/buffers.h
@@ -12,6 +12,8 @@
#ifndef TOR_BUFFERS_H
#define TOR_BUFFERS_H
+#include "testsupport.h"
+
buf_t *buf_new(void);
buf_t *buf_new_with_capacity(size_t size);
void buf_free(buf_t *buf);
@@ -51,6 +53,8 @@ int fetch_from_buf_line(buf_t *buf, char *data_out, size_t *data_len);
int peek_buf_has_control0_command(buf_t *buf);
+int fetch_ext_or_command_from_buf(buf_t *buf, ext_or_cmd_t **out);
+
#ifdef USE_BUFFEREVENTS
int fetch_var_cell_from_evbuffer(struct evbuffer *buf, var_cell_t **out,
int linkproto);
@@ -66,6 +70,8 @@ int peek_evbuffer_has_control0_command(struct evbuffer *buf);
int write_to_evbuffer_zlib(struct evbuffer *buf, tor_zlib_state_t *state,
const char *data, size_t data_len,
int done);
+int fetch_ext_or_command_from_evbuffer(struct evbuffer *buf,
+ ext_or_cmd_t **out);
#endif
#ifdef USE_BUFFEREVENTS
@@ -75,6 +81,8 @@ int write_to_evbuffer_zlib(struct evbuffer *buf, tor_zlib_state_t *state,
#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))
+#define generic_buffer_fetch_ext_or_cmd(b, out) \
+ fetch_ext_or_command_from_evbuffer((b), (out))
#else
#define generic_buffer_new() buf_new()
#define generic_buffer_len(b) buf_datalen((b))
@@ -82,6 +90,8 @@ int write_to_evbuffer_zlib(struct evbuffer *buf, tor_zlib_state_t *state,
#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))
+#define generic_buffer_fetch_ext_or_cmd(b, out) \
+ fetch_ext_or_command_from_buf((b), (out))
#endif
int generic_buffer_set_to_copy(generic_buffer_t **output,
const generic_buffer_t *input);
@@ -89,7 +99,7 @@ int generic_buffer_set_to_copy(generic_buffer_t **output,
void assert_buf_ok(buf_t *buf);
#ifdef BUFFERS_PRIVATE
-int buf_find_string_offset(const buf_t *buf, const char *s, size_t n);
+STATIC int buf_find_string_offset(const buf_t *buf, const char *s, size_t n);
#endif
#endif
diff --git a/src/or/channel.c b/src/or/channel.c
index 98c23d91e..48bbf7902 100644
--- a/src/or/channel.c
+++ b/src/or/channel.c
@@ -2379,8 +2379,14 @@ channel_do_open_actions(channel_t *chan)
/* only report it to the geoip module if it's not a known router */
if (!router_get_by_id_digest(chan->identity_digest)) {
if (channel_get_addr_if_possible(chan, &remote_addr)) {
- geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &remote_addr,
+ char *transport_name = NULL;
+ if (chan->get_transport_name(chan, &transport_name) < 0)
+ transport_name = NULL;
+
+ geoip_note_client_seen(GEOIP_CLIENT_CONNECT,
+ &remote_addr, transport_name,
now);
+ tor_free(transport_name);
}
/* Otherwise the underlying transport can't tell us this, so skip it */
}
@@ -3090,7 +3096,7 @@ channel_get_for_extend(const char *digest,
if (chan->state != CHANNEL_STATE_OPEN) {
/* If the address matches, don't launch a new connection for this
* circuit. */
- if (!channel_matches_target_addr_for_extend(chan, target_addr))
+ if (channel_matches_target_addr_for_extend(chan, target_addr))
++n_inprogress_goodaddr;
continue;
}
@@ -4106,7 +4112,7 @@ channel_matches_extend_info(channel_t *chan, extend_info_t *extend_info)
}
/**
- * Check if a channel matches a given target address
+ * Check if a channel matches a given target address; return true iff we do.
*
* This function calls into the lower layer and asks if this channel thinks
* it matches a given target address for circuit extension purposes.
diff --git a/src/or/channel.h b/src/or/channel.h
index 8f082206b..430a0251a 100644
--- a/src/or/channel.h
+++ b/src/or/channel.h
@@ -83,6 +83,8 @@ struct channel_s {
* available.
*/
int (*get_remote_addr)(channel_t *, tor_addr_t *);
+ int (*get_transport_name)(channel_t *chan, char **transport_out);
+
#define GRD_FLAG_ORIGINAL 1
#define GRD_FLAG_ADDR_ONLY 2
/*
diff --git a/src/or/channeltls.c b/src/or/channeltls.c
index 60693daeb..7303c5a72 100644
--- a/src/or/channeltls.c
+++ b/src/or/channeltls.c
@@ -55,6 +55,8 @@ static void channel_tls_close_method(channel_t *chan);
static const char * channel_tls_describe_transport_method(channel_t *chan);
static int
channel_tls_get_remote_addr_method(channel_t *chan, tor_addr_t *addr_out);
+static int
+channel_tls_get_transport_name_method(channel_t *chan, char **transport_out);
static const char *
channel_tls_get_remote_descr_method(channel_t *chan, int flags);
static int channel_tls_has_queued_writes_method(channel_t *chan);
@@ -114,6 +116,7 @@ channel_tls_common_init(channel_tls_t *tlschan)
chan->describe_transport = channel_tls_describe_transport_method;
chan->get_remote_addr = channel_tls_get_remote_addr_method;
chan->get_remote_descr = channel_tls_get_remote_descr_method;
+ chan->get_transport_name = channel_tls_get_transport_name_method;
chan->has_queued_writes = channel_tls_has_queued_writes_method;
chan->is_canonical = channel_tls_is_canonical_method;
chan->matches_extend_info = channel_tls_matches_extend_info_method;
@@ -406,6 +409,30 @@ channel_tls_get_remote_addr_method(channel_t *chan, tor_addr_t *addr_out)
}
/**
+ * Get the name of the pluggable transport used by a channel_tls_t.
+ *
+ * This implements the get_transport_name for channel_tls_t. If the
+ * channel uses a pluggable transport, copy its name to
+ * <b>transport_out</b> and return 0. If the channel did not use a
+ * pluggable transport, return -1. */
+
+static int
+channel_tls_get_transport_name_method(channel_t *chan, char **transport_out)
+{
+ channel_tls_t *tlschan = BASE_CHAN_TO_TLS(chan);
+
+ tor_assert(tlschan);
+ tor_assert(transport_out);
+ tor_assert(tlschan->conn);
+
+ if (!tlschan->conn->ext_or_transport)
+ return -1;
+
+ *transport_out = tor_strdup(tlschan->conn->ext_or_transport);
+ return 0;
+}
+
+/**
* Get endpoint description of a channel_tls_t
*
* This implements the get_remote_descr method for channel_tls_t; it returns
@@ -546,7 +573,7 @@ channel_tls_matches_extend_info_method(channel_t *chan,
}
/**
- * Check if we match a target address
+ * Check if we match a target address; return true iff we do.
*
* This implements the matches_target method for channel_tls t_; the upper
* layer wants to know if this channel matches a target address when extending
@@ -563,8 +590,7 @@ channel_tls_matches_target_method(channel_t *chan,
tor_assert(target);
tor_assert(tlschan->conn);
- return tor_addr_compare(&(tlschan->conn->real_addr),
- target, CMP_EXACT);
+ return tor_addr_eq(&(tlschan->conn->real_addr), target);
}
/**
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index 6bf18590a..a4144e800 100644
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@ -8,7 +8,7 @@
* \file circuitlist.c
* \brief Manage the global circuit list.
**/
-
+#define CIRCUITLIST_PRIVATE
#include "or.h"
#include "channel.h"
#include "circuitbuild.h"
@@ -42,7 +42,6 @@ struct global_circuitlist_s global_circuitlist =
/** A list of all the circuits in CIRCUIT_STATE_CHAN_WAIT. */
static smartlist_t *circuits_pending_chans = NULL;
-static void circuit_free(circuit_t *circ);
static void circuit_free_cpath(crypt_path_t *cpath);
static void circuit_free_cpath_node(crypt_path_t *victim);
static void cpath_ref_decref(crypt_path_reference_t *cpath_ref);
@@ -653,6 +652,7 @@ init_circuit_base(circuit_t *circ)
circ->package_window = circuit_initial_package_window();
circ->deliver_window = CIRCWINDOW_START;
+ cell_queue_init(&circ->n_chan_cells);
TOR_LIST_INSERT_HEAD(&global_circuitlist, circ, head);
}
@@ -698,6 +698,7 @@ or_circuit_new(circid_t p_circ_id, channel_t *p_chan)
circuit_set_p_circid_chan(circ, p_circ_id, p_chan);
circ->remaining_relay_early_cells = MAX_RELAY_EARLY_CELLS_PER_CIRCUIT;
+ cell_queue_init(&circ->p_chan_cells);
init_circuit_base(TO_CIRCUIT(circ));
@@ -706,7 +707,7 @@ or_circuit_new(circid_t p_circ_id, channel_t *p_chan)
/** Deallocate space associated with circ.
*/
-static void
+STATIC void
circuit_free(circuit_t *circ)
{
void *mem;
@@ -1607,12 +1608,14 @@ marked_circuit_free_cells(circuit_t *circ)
}
/** Return the number of cells used by the circuit <b>c</b>'s cell queues. */
-static size_t
+STATIC size_t
n_cells_in_circ_queues(const circuit_t *c)
{
size_t n = c->n_chan_cells.n;
- if (! CIRCUIT_IS_ORIGIN(c))
- n += TO_OR_CIRCUIT((circuit_t*)c)->p_chan_cells.n;
+ if (! CIRCUIT_IS_ORIGIN(c)) {
+ circuit_t *cc = (circuit_t *) c;
+ n += TO_OR_CIRCUIT(cc)->p_chan_cells.n;
+ }
return n;
}
diff --git a/src/or/circuitlist.h b/src/or/circuitlist.h
index 4726b3be5..a43315d23 100644
--- a/src/or/circuitlist.h
+++ b/src/or/circuitlist.h
@@ -12,6 +12,8 @@
#ifndef TOR_CIRCUITLIST_H
#define TOR_CIRCUITLIST_H
+#include "testsupport.h"
+
TOR_LIST_HEAD(global_circuitlist_s, circuit_t);
struct global_circuitlist_s* circuit_get_global_list_(void);
@@ -70,5 +72,10 @@ void circuits_handle_oom(size_t current_allocation);
void channel_note_destroy_pending(channel_t *chan, circid_t id);
void channel_note_destroy_not_pending(channel_t *chan, circid_t id);
+#ifdef CIRCUITLIST_PRIVATE
+STATIC void circuit_free(circuit_t *circ);
+STATIC size_t n_cells_in_circ_queues(const circuit_t *c);
+#endif
+
#endif
diff --git a/src/or/circuitmux.c b/src/or/circuitmux.c
index c84e0ce09..47b423066 100644
--- a/src/or/circuitmux.c
+++ b/src/or/circuitmux.c
@@ -383,6 +383,7 @@ circuitmux_alloc(void)
rv = tor_malloc_zero(sizeof(*rv));
rv->chanid_circid_map = tor_malloc_zero(sizeof(*( rv->chanid_circid_map)));
HT_INIT(chanid_circid_muxinfo_map, rv->chanid_circid_map);
+ cell_queue_init(&rv->destroy_cell_queue);
return rv;
}
@@ -510,7 +511,7 @@ circuitmux_mark_destroyed_circids_usable(circuitmux_t *cmux, channel_t *chan)
{
packed_cell_t *cell;
int n_bad = 0;
- for (cell = cmux->destroy_cell_queue.head; cell; cell = cell->next) {
+ TOR_SIMPLEQ_FOREACH(cell, &cmux->destroy_cell_queue.head, next) {
circid_t circid = 0;
if (packed_cell_is_destroy(chan, cell, &circid)) {
channel_mark_circid_usable(chan, circid);
@@ -922,9 +923,9 @@ circuitmux_num_circuits(circuitmux_t *cmux)
* Attach a circuit to a circuitmux, for the specified direction.
*/
-void
-circuitmux_attach_circuit(circuitmux_t *cmux, circuit_t *circ,
- cell_direction_t direction)
+MOCK_IMPL(void,
+circuitmux_attach_circuit,(circuitmux_t *cmux, circuit_t *circ,
+ cell_direction_t direction))
{
channel_t *chan = NULL;
uint64_t channel_id;
@@ -1071,8 +1072,8 @@ circuitmux_attach_circuit(circuitmux_t *cmux, circuit_t *circ,
* no-op if not attached.
*/
-void
-circuitmux_detach_circuit(circuitmux_t *cmux, circuit_t *circ)
+MOCK_IMPL(void,
+circuitmux_detach_circuit,(circuitmux_t *cmux, circuit_t *circ))
{
chanid_circid_muxinfo_t search, *hashent = NULL;
/*
diff --git a/src/or/circuitmux.h b/src/or/circuitmux.h
index a6bc415cd..ee2f5d153 100644
--- a/src/or/circuitmux.h
+++ b/src/or/circuitmux.h
@@ -10,6 +10,7 @@
#define TOR_CIRCUITMUX_H
#include "or.h"
+#include "testsupport.h"
typedef struct circuitmux_policy_s circuitmux_policy_t;
typedef struct circuitmux_policy_data_s circuitmux_policy_data_t;
@@ -127,9 +128,11 @@ void circuitmux_notify_xmit_cells(circuitmux_t *cmux, circuit_t *circ,
void circuitmux_notify_xmit_destroy(circuitmux_t *cmux);
/* Circuit interface */
-void circuitmux_attach_circuit(circuitmux_t *cmux, circuit_t *circ,
- cell_direction_t direction);
-void circuitmux_detach_circuit(circuitmux_t *cmux, circuit_t *circ);
+MOCK_DECL(void, circuitmux_attach_circuit, (circuitmux_t *cmux,
+ circuit_t *circ,
+ cell_direction_t direction));
+MOCK_DECL(void, circuitmux_detach_circuit,
+ (circuitmux_t *cmux, circuit_t *circ));
void circuitmux_clear_num_cells(circuitmux_t *cmux, circuit_t *circ);
void circuitmux_set_num_cells(circuitmux_t *cmux, circuit_t *circ,
unsigned int n_cells);
diff --git a/src/or/circuitstats.c b/src/or/circuitstats.c
index 1d7812bf2..95129f9a4 100644
--- a/src/or/circuitstats.c
+++ b/src/or/circuitstats.c
@@ -29,9 +29,13 @@
/* XXXX024 Make this static; add accessor functions. */
circuit_build_times_t circ_times;
+#ifdef TOR_UNIT_TESTS
/** If set, we're running the unit tests: we should avoid clobbering
* our state file or accessing get_options() or get_or_state() */
static int unit_tests = 0;
+#else
+#define unit_tests 0
+#endif
/**
* This function decides if CBT learning should be disabled. It returns
@@ -438,7 +442,7 @@ circuit_build_times_get_initial_timeout(void)
* Leave estimated parameters, timeout and network liveness intact
* for future use.
*/
-void
+STATIC void
circuit_build_times_reset(circuit_build_times_t *cbt)
{
memset(cbt->circuit_build_times, 0, sizeof(cbt->circuit_build_times));
@@ -949,7 +953,7 @@ circuit_build_times_parse_state(circuit_build_times_t *cbt,
* an acceptable approximation because we are only concerned with the
* accuracy of the CDF of the tail.
*/
-int
+STATIC int
circuit_build_times_update_alpha(circuit_build_times_t *cbt)
{
build_time_t *x=cbt->circuit_build_times;
@@ -1033,7 +1037,7 @@ circuit_build_times_update_alpha(circuit_build_times_t *cbt)
*
* Return value is in milliseconds.
*/
-double
+STATIC double
circuit_build_times_calculate_timeout(circuit_build_times_t *cbt,
double quantile)
{
@@ -1050,6 +1054,7 @@ circuit_build_times_calculate_timeout(circuit_build_times_t *cbt,
return ret;
}
+#ifdef TOR_UNIT_TESTS
/** Pareto CDF */
double
circuit_build_times_cdf(circuit_build_times_t *cbt, double x)
@@ -1060,7 +1065,9 @@ circuit_build_times_cdf(circuit_build_times_t *cbt, double x)
tor_assert(0 <= ret && ret <= 1.0);
return ret;
}
+#endif
+#ifdef TOR_UNIT_TESTS
/**
* Generate a synthetic time using our distribution parameters.
*
@@ -1093,7 +1100,9 @@ circuit_build_times_generate_sample(circuit_build_times_t *cbt,
tor_assert(ret > 0);
return ret;
}
+#endif
+#ifdef TOR_UNIT_TESTS
/**
* Estimate an initial alpha parameter by solving the quantile
* function with a quantile point and a specific timeout value.
@@ -1114,6 +1123,7 @@ circuit_build_times_initial_alpha(circuit_build_times_t *cbt,
(tor_mathlog(cbt->Xm)-tor_mathlog(timeout_ms));
tor_assert(cbt->alpha > 0);
}
+#endif
/**
* Returns true if we need circuits to be built
@@ -1282,7 +1292,7 @@ circuit_build_times_network_check_live(circuit_build_times_t *cbt)
* to restart the process of building test circuits and estimating a
* new timeout.
*/
-int
+STATIC int
circuit_build_times_network_check_changed(circuit_build_times_t *cbt)
{
int total_build_times = cbt->total_build_times;
@@ -1546,6 +1556,8 @@ circuit_build_times_set_timeout(circuit_build_times_t *cbt)
cbt->total_build_times);
}
}
+
+#ifdef TOR_UNIT_TESTS
/** Make a note that we're running unit tests (rather than running Tor
* itself), so we avoid clobbering our state file. */
void
@@ -1553,4 +1565,5 @@ circuitbuild_running_unit_tests(void)
{
unit_tests = 1;
}
+#endif
diff --git a/src/or/circuitstats.h b/src/or/circuitstats.h
index 87dce99f4..53ba2b2d2 100644
--- a/src/or/circuitstats.h
+++ b/src/or/circuitstats.h
@@ -38,19 +38,23 @@ double circuit_build_times_timeout_rate(const circuit_build_times_t *cbt);
double circuit_build_times_close_rate(const circuit_build_times_t *cbt);
#ifdef CIRCUITSTATS_PRIVATE
-double circuit_build_times_calculate_timeout(circuit_build_times_t *cbt,
+STATIC double circuit_build_times_calculate_timeout(circuit_build_times_t *cbt,
double quantile);
+STATIC int circuit_build_times_update_alpha(circuit_build_times_t *cbt);
+STATIC void circuit_build_times_reset(circuit_build_times_t *cbt);
+
+/* Network liveness functions */
+STATIC int circuit_build_times_network_check_changed(
+ circuit_build_times_t *cbt);
+#endif
+
+#ifdef TOR_UNIT_TESTS
build_time_t circuit_build_times_generate_sample(circuit_build_times_t *cbt,
double q_lo, double q_hi);
+double circuit_build_times_cdf(circuit_build_times_t *cbt, double x);
void circuit_build_times_initial_alpha(circuit_build_times_t *cbt,
double quantile, double time_ms);
-int circuit_build_times_update_alpha(circuit_build_times_t *cbt);
-double circuit_build_times_cdf(circuit_build_times_t *cbt, double x);
void circuitbuild_running_unit_tests(void);
-void circuit_build_times_reset(circuit_build_times_t *cbt);
-
-/* Network liveness functions */
-int circuit_build_times_network_check_changed(circuit_build_times_t *cbt);
#endif
/* Network liveness functions */
@@ -58,8 +62,5 @@ void circuit_build_times_network_is_live(circuit_build_times_t *cbt);
int circuit_build_times_network_check_live(circuit_build_times_t *cbt);
void circuit_build_times_network_circ_success(circuit_build_times_t *cbt);
-/* DOCDOC circuit_build_times_get_bw_scale */
-int circuit_build_times_get_bw_scale(networkstatus_t *ns);
-
#endif
diff --git a/src/or/config.c b/src/or/config.c
index e3ffbf208..e746da220 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -10,7 +10,6 @@
**/
#define CONFIG_PRIVATE
-
#include "or.h"
#include "addressmap.h"
#include "channel.h"
@@ -40,11 +39,13 @@
#include "rendservice.h"
#include "rephist.h"
#include "router.h"
+#include "sandbox.h"
#include "util.h"
#include "routerlist.h"
#include "routerset.h"
#include "statefile.h"
#include "transports.h"
+#include "ext_orport.h"
#ifdef _WIN32
#include <shlobj.h>
#endif
@@ -230,6 +231,7 @@ static config_var_t option_vars_[] = {
V(ExitPolicyRejectPrivate, BOOL, "1"),
V(ExitPortStatistics, BOOL, "0"),
V(ExtendAllowPrivateAddresses, BOOL, "0"),
+ VPORT(ExtORPort, LINELIST, NULL),
V(ExtraInfoStatistics, BOOL, "1"),
V(FallbackDir, LINELIST, NULL),
@@ -281,6 +283,7 @@ static config_var_t option_vars_[] = {
V(IPv6Exit, BOOL, "0"),
VAR("ServerTransportPlugin", LINELIST, ServerTransportPlugin, NULL),
V(ServerTransportListenAddr, LINELIST, NULL),
+ V(ServerTransportOptions, LINELIST, NULL),
V(Socks4Proxy, STRING, NULL),
V(Socks5Proxy, STRING, NULL),
V(Socks5ProxyUsername, STRING, NULL),
@@ -314,7 +317,7 @@ static config_var_t option_vars_[] = {
OBSOLETE("NoPublish"),
VAR("NodeFamily", LINELIST, NodeFamilies, NULL),
V(NumCPUs, UINT, "0"),
- V(NumDirectoryGuards, UINT, "3"),
+ V(NumDirectoryGuards, UINT, "0"),
V(NumEntryGuards, UINT, "3"),
V(ORListenAddress, LINELIST, NULL),
VPORT(ORPort, LINELIST, NULL),
@@ -370,6 +373,7 @@ static config_var_t option_vars_[] = {
V(RunAsDaemon, BOOL, "0"),
// V(RunTesting, BOOL, "0"),
OBSOLETE("RunTesting"), // currently unused
+ V(Sandbox, BOOL, "0"),
V(SafeLogging, STRING, "1"),
V(SafeSocks, BOOL, "0"),
V(ServerDNSAllowBrokenConfig, BOOL, "1"),
@@ -508,10 +512,6 @@ static const config_var_t testing_tor_network_defaults[] = {
#ifdef _WIN32
static char *get_windows_conf_root(void);
#endif
-static int options_validate(or_options_t *old_options,
- or_options_t *options,
- or_options_t *default_options,
- int from_setconf, char **msg);
static int options_act_reversible(const or_options_t *old_options, char **msg);
static int options_act(const or_options_t *old_options);
static int options_transition_allowed(const or_options_t *old,
@@ -555,7 +555,7 @@ static void config_maybe_load_geoip_files_(const or_options_t *options,
#define OR_OPTIONS_MAGIC 9090909
/** Configuration format for or_options_t. */
-static config_format_t options_format = {
+STATIC config_format_t options_format = {
sizeof(or_options_t),
OR_OPTIONS_MAGIC,
STRUCT_OFFSET(or_options_t, magic_),
@@ -711,7 +711,7 @@ get_short_version(void)
/** Release additional memory allocated in options
*/
-static void
+STATIC void
or_options_free(or_options_t *options)
{
if (!options)
@@ -1005,6 +1005,7 @@ options_act_reversible(const or_options_t *old_options, char **msg)
int set_conn_limit = 0;
int r = -1;
int logs_marked = 0;
+ int old_min_log_level = get_min_log_level();
/* Daemonize _first_, since we only want to open most of this stuff in
* the subprocess. Libevent bases can't be reliably inherited across
@@ -1143,6 +1144,8 @@ options_act_reversible(const or_options_t *old_options, char **msg)
goto rollback;
}
+ sandbox_set_debugging_fd(get_err_logging_fd());
+
commit:
r = 0;
if (logs_marked) {
@@ -1153,6 +1156,13 @@ options_act_reversible(const or_options_t *old_options, char **msg)
control_adjust_event_log_severity();
tor_free(severity);
}
+ if (get_min_log_level() >= LOG_INFO &&
+ get_min_log_level() != old_min_log_level) {
+ log_warn(LD_GENERAL, "Your log may contain sensitive information - you're "
+ "logging above \"notice\". Please log safely. Don't log unless "
+ "it serves an important reason. Overwrite the log afterwards.");
+ }
+
SMARTLIST_FOREACH(replaced_listeners, connection_t *, conn,
{
log_notice(LD_NET, "Closing old %s on %s:%d",
@@ -1335,6 +1345,13 @@ options_act(const or_options_t *old_options)
}
#endif
+ if (options->SafeLogging_ != SAFELOG_SCRUB_ALL &&
+ (!old_options || old_options->SafeLogging_ != options->SafeLogging_)) {
+ log_warn(LD_GENERAL, "Your log may contain sensitive information - you "
+ "disabled SafeLogging. Please log safely. Don't log unless it "
+ "serves an important reason. Overwrite the log afterwards.");
+ }
+
if (options->Bridges) {
mark_bridge_list();
for (cl = options->Bridges; cl; cl = cl->next) {
@@ -1458,8 +1475,14 @@ options_act(const or_options_t *old_options)
return -1;
}
- if (init_cookie_authentication(options->CookieAuthentication) < 0) {
- log_warn(LD_CONFIG,"Error creating cookie authentication file.");
+ if (init_control_cookie_authentication(options->CookieAuthentication) < 0) {
+ log_warn(LD_CONFIG,"Error creating control cookie authentication file.");
+ return -1;
+ }
+
+ /* If we have an ExtORPort, initialize its auth cookie. */
+ if (init_ext_or_cookie_authentication(!!options->ExtORPort_lines) < 0) {
+ log_warn(LD_CONFIG,"Error creating Extended ORPort cookie file.");
return -1;
}
@@ -2331,7 +2354,7 @@ compute_publishserverdescriptor(or_options_t *options)
* Log line should stay empty. If it's 0, then give us a default log
* if there are no logs defined.
*/
-static int
+STATIC int
options_validate(or_options_t *old_options, or_options_t *options,
or_options_t *default_options, int from_setconf, char **msg)
{
@@ -3130,6 +3153,19 @@ options_validate(or_options_t *old_options, or_options_t *options,
"ServerTransportListenAddr line will be ignored.");
}
+ for (cl = options->ServerTransportOptions; cl; cl = cl->next) {
+ /** If get_options_from_transport_options_line() fails with
+ 'transport' being NULL, it means that something went wrong
+ while parsing the ServerTransportOptions line. */
+ smartlist_t *options_sl =
+ get_options_from_transport_options_line(cl->value, NULL);
+ if (!options_sl)
+ REJECT("ServerTransportOptions did not parse. See logs for details.");
+
+ SMARTLIST_FOREACH(options_sl, char *, cp, tor_free(cp));
+ smartlist_free(options_sl);
+ }
+
if (options->ConstrainedSockets) {
/* If the user wants to constrain socket buffer use, make sure the desired
* limit is between MIN|MAX_TCPSOCK_BUFFER in k increments. */
@@ -3800,6 +3836,7 @@ options_init_from_torrc(int argc, char **argv)
}
if (command == CMD_HASH_PASSWORD) {
+ cf_defaults = tor_strdup("");
cf = tor_strdup("");
} else {
cf_defaults = load_torrc_from_disk(argc, argv, 1);
@@ -3871,6 +3908,10 @@ options_init_from_string(const char *cf_defaults, const char *cf,
newdefaultoptions = config_dup(&options_format, newoptions);
}
+ if (newdefaultoptions == NULL) {
+ newdefaultoptions = config_dup(&options_format, global_default_options);
+ }
+
/* Go through command-line variables too */
retval = config_assign(&options_format, newoptions,
global_cmdline_options, 0, 0, msg);
@@ -4559,6 +4600,63 @@ get_bindaddr_from_transport_listen_line(const char *line,const char *transport)
return addrport;
}
+/** Given a ServerTransportOptions <b>line</b>, return a smartlist
+ * with the options. Return NULL if the line was not well-formed.
+ *
+ * If <b>transport</b> is set, return NULL if the line is not
+ * referring to <b>transport</b>.
+ *
+ * The returned smartlist and its strings are allocated on the heap
+ * and it's the responsibility of the caller to free it. */
+smartlist_t *
+get_options_from_transport_options_line(const char *line,const char *transport)
+{
+ smartlist_t *items = smartlist_new();
+ smartlist_t *options = smartlist_new();
+ const char *parsed_transport = NULL;
+
+ smartlist_split_string(items, line, NULL,
+ SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
+
+ if (smartlist_len(items) < 2) {
+ log_warn(LD_CONFIG,"Too few arguments on ServerTransportOptions line.");
+ goto err;
+ }
+
+ parsed_transport = smartlist_get(items, 0);
+ /* If 'transport' is given, check if it matches the one on the line */
+ if (transport && strcmp(transport, parsed_transport))
+ goto err;
+
+ SMARTLIST_FOREACH_BEGIN(items, const char *, option) {
+ if (option_sl_idx == 0) /* skip the transport field (first field)*/
+ continue;
+
+ /* validate that it's a k=v value */
+ if (!string_is_key_value(LOG_WARN, option)) {
+ log_warn(LD_CONFIG, "%s is not a k=v value.", escaped(option));
+ goto err;
+ }
+
+ /* add it to the options smartlist */
+ smartlist_add(options, tor_strdup(option));
+ log_debug(LD_CONFIG, "Added %s to the list of options", escaped(option));
+ } SMARTLIST_FOREACH_END(option);
+
+ goto done;
+
+ err:
+ SMARTLIST_FOREACH(options, char*, s, tor_free(s));
+ smartlist_free(options);
+ options = NULL;
+
+ done:
+ SMARTLIST_FOREACH(items, char*, s, tor_free(s));
+ smartlist_free(items);
+
+ return options;
+}
+
/** Given the name of a pluggable transport in <b>transport</b>, check
* the configuration file to see if the user has explicitly asked for
* it to listen on a specific port. Return a <address:port> string if
@@ -4579,6 +4677,26 @@ get_transport_bindaddr_from_config(const char *transport)
return NULL;
}
+/** Given the name of a pluggable transport in <b>transport</b>, check
+ * the configuration file to see if the user has asked us to pass any
+ * parameters to the pluggable transport. Return a smartlist
+ * containing the parameters, otherwise NULL. */
+smartlist_t *
+get_options_for_server_transport(const char *transport)
+{
+ config_line_t *cl;
+ const or_options_t *options = get_options();
+
+ for (cl = options->ServerTransportOptions; cl; cl = cl->next) {
+ smartlist_t *options_sl =
+ get_options_from_transport_options_line(cl->value, transport);
+ if (options_sl)
+ return options_sl;
+ }
+
+ return NULL;
+}
+
/** Read the contents of a ServerTransportPlugin line from
* <b>line</b>. Return 0 if the line is well-formed, and -1 if it
* isn't.
@@ -4983,6 +5101,27 @@ warn_nonlocal_client_ports(const smartlist_t *ports, const char *portname,
} SMARTLIST_FOREACH_END(port);
}
+/** Warn for every Extended ORPort port in <b>ports</b> that is on a
+ * publicly routable address. */
+static void
+warn_nonlocal_ext_orports(const smartlist_t *ports, const char *portname)
+{
+ SMARTLIST_FOREACH_BEGIN(ports, const port_cfg_t *, port) {
+ if (port->type != CONN_TYPE_EXT_OR_LISTENER)
+ continue;
+ if (port->is_unix_addr)
+ continue;
+ /* XXX maybe warn even if address is RFC1918? */
+ if (!tor_addr_is_internal(&port->addr, 1)) {
+ log_warn(LD_CONFIG, "You specified a public address '%s' for %sPort. "
+ "This is not advised; this address is supposed to only be "
+ "exposed on localhost so that your pluggable transport "
+ "proxies can connect to it.",
+ fmt_addrport(&port->addr, port->port), portname);
+ }
+ } SMARTLIST_FOREACH_END(port);
+}
+
/** Given a list of port_cfg_t in <b>ports</b>, warn any controller port there
* is listening on any non-loopback address. If <b>forbid</b> is true,
* then emit a stronger warning and remove the port from the list.
@@ -5083,6 +5222,7 @@ parse_port_config(smartlist_t *out,
smartlist_t *elts;
int retval = -1;
const unsigned is_control = (listener_type == CONN_TYPE_CONTROL_LISTENER);
+ const unsigned is_ext_orport = (listener_type == CONN_TYPE_EXT_OR_LISTENER);
const unsigned allow_no_options = flags & CL_PORT_NO_OPTIONS;
const unsigned use_server_options = flags & CL_PORT_SERVER_OPTIONS;
const unsigned warn_nonlocal = flags & CL_PORT_WARN_NONLOCAL;
@@ -5160,6 +5300,8 @@ parse_port_config(smartlist_t *out,
if (warn_nonlocal && out) {
if (is_control)
warn_nonlocal_controller_ports(out, forbid_nonlocal);
+ else if (is_ext_orport)
+ warn_nonlocal_ext_orports(out, portname);
else
warn_nonlocal_client_ports(out, portname, listener_type);
}
@@ -5433,6 +5575,8 @@ parse_port_config(smartlist_t *out,
if (warn_nonlocal && out) {
if (is_control)
warn_nonlocal_controller_ports(out, forbid_nonlocal);
+ else if (is_ext_orport)
+ warn_nonlocal_ext_orports(out, portname);
else
warn_nonlocal_client_ports(out, portname, listener_type);
}
@@ -5579,6 +5723,14 @@ parse_ports(or_options_t *options, int validate_only,
goto err;
}
if (parse_port_config(ports,
+ options->ExtORPort_lines, NULL,
+ "ExtOR", CONN_TYPE_EXT_OR_LISTENER,
+ "127.0.0.1", 0,
+ CL_PORT_SERVER_OPTIONS|CL_PORT_WARN_NONLOCAL) < 0) {
+ *msg = tor_strdup("Invalid ExtORPort configuration");
+ goto err;
+ }
+ if (parse_port_config(ports,
options->DirPort_lines, options->DirListenAddress,
"Dir", CONN_TYPE_DIR_LISTENER,
"0.0.0.0", 0,
@@ -5613,6 +5765,8 @@ parse_ports(or_options_t *options, int validate_only,
!! count_real_listeners(ports, CONN_TYPE_DIR_LISTENER);
options->DNSPort_set =
!! count_real_listeners(ports, CONN_TYPE_AP_DNS_LISTENER);
+ options->ExtORPort_set =
+ !! count_real_listeners(ports, CONN_TYPE_EXT_OR_LISTENER);
if (!validate_only) {
if (configured_ports) {
@@ -6311,3 +6465,58 @@ config_maybe_load_geoip_files_(const or_options_t *options,
config_load_geoip_file_(AF_INET6, options->GeoIPv6File, "geoip6");
}
+/** Initialize cookie authentication (used so far by the ControlPort
+ * and Extended ORPort).
+ *
+ * Allocate memory and create a cookie (of length <b>cookie_len</b>)
+ * in <b>cookie_out</b>.
+ * Then write it down to <b>fname</b> and prepend it with <b>header</b>.
+ *
+ * If the whole procedure was successful, set
+ * <b>cookie_is_set_out</b> to True. */
+int
+init_cookie_authentication(const char *fname, const char *header,
+ int cookie_len,
+ uint8_t **cookie_out, int *cookie_is_set_out)
+{
+ char cookie_file_str_len = strlen(header) + cookie_len;
+ char *cookie_file_str = tor_malloc(cookie_file_str_len);
+ int retval = -1;
+
+ /* We don't want to generate a new cookie every time we call
+ * options_act(). One should be enough. */
+ if (*cookie_is_set_out) {
+ retval = 0; /* we are all set */
+ goto done;
+ }
+
+ /* If we've already set the cookie, free it before re-setting
+ it. This can happen if we previously generated a cookie, but
+ couldn't write it to a disk. */
+ if (*cookie_out)
+ tor_free(*cookie_out);
+
+ /* Generate the cookie */
+ *cookie_out = tor_malloc(cookie_len);
+ if (crypto_rand((char *)*cookie_out, cookie_len) < 0)
+ goto done;
+
+ /* Create the string that should be written on the file. */
+ memcpy(cookie_file_str, header, strlen(header));
+ memcpy(cookie_file_str+strlen(header), *cookie_out, cookie_len);
+ if (write_bytes_to_file(fname, cookie_file_str, cookie_file_str_len, 1)) {
+ log_warn(LD_FS,"Error writing auth cookie to %s.", escaped(fname));
+ goto done;
+ }
+
+ /* Success! */
+ log_info(LD_GENERAL, "Generated auth cookie file in '%s'.", escaped(fname));
+ *cookie_is_set_out = 1;
+ retval = 0;
+
+ done:
+ memwipe(cookie_file_str, 0, cookie_file_str_len);
+ tor_free(cookie_file_str);
+ return retval;
+}
+
diff --git a/src/or/config.h b/src/or/config.h
index 0250f645d..eb16e7461 100644
--- a/src/or/config.h
+++ b/src/or/config.h
@@ -90,10 +90,11 @@ uint32_t get_effective_bwburst(const or_options_t *options);
char *get_transport_bindaddr_from_config(const char *transport);
-#ifdef CONFIG_PRIVATE
-/* Used only by config.c and test.c */
+int init_cookie_authentication(const char *fname, const char *header,
+ int cookie_len,
+ uint8_t **cookie_out, int *cookie_is_set_out);
+
or_options_t *options_new(void);
-#endif
void config_register_addressmaps(const or_options_t *options);
/* XXXX024 move to connection_edge.h */
@@ -109,12 +110,27 @@ typedef struct bridge_line_t {
char *transport_name; /* The name of the pluggable transport that
should be used to connect to the bridge. */
char digest[DIGEST_LEN]; /* The bridge's identity key digest. */
- smartlist_t *socks_args;; /* SOCKS arguments for the pluggable
+ smartlist_t *socks_args; /* SOCKS arguments for the pluggable
transport proxy. */
} bridge_line_t;
void bridge_line_free(bridge_line_t *bridge_line);
bridge_line_t *parse_bridge_line(const char *line);
+smartlist_t *get_options_from_transport_options_line(const char *line,
+ const char *transport);
+smartlist_t *get_options_for_server_transport(const char *transport);
+
+#ifdef CONFIG_PRIVATE
+#ifdef TOR_UNIT_TESTS
+extern struct config_format_t options_format;
+#endif
+
+STATIC void or_options_free(or_options_t *options);
+STATIC int options_validate(or_options_t *old_options,
+ or_options_t *options,
+ or_options_t *default_options,
+ int from_setconf, char **msg);
+#endif
#endif
diff --git a/src/or/confparse.c b/src/or/confparse.c
index eb0362f49..41055791e 100644
--- a/src/or/confparse.c
+++ b/src/or/confparse.c
@@ -1126,20 +1126,36 @@ static struct unit_table_t memory_units[] = {
{ "kbytes", 1<<10 },
{ "kilobyte", 1<<10 },
{ "kilobytes", 1<<10 },
+ { "kilobits", 1<<7 },
+ { "kilobit", 1<<7 },
+ { "kbits", 1<<7 },
+ { "kbit", 1<<7 },
{ "m", 1<<20 },
{ "mb", 1<<20 },
{ "mbyte", 1<<20 },
{ "mbytes", 1<<20 },
{ "megabyte", 1<<20 },
{ "megabytes", 1<<20 },
+ { "megabits", 1<<17 },
+ { "megabit", 1<<17 },
+ { "mbits", 1<<17 },
+ { "mbit", 1<<17 },
{ "gb", 1<<30 },
{ "gbyte", 1<<30 },
{ "gbytes", 1<<30 },
{ "gigabyte", 1<<30 },
{ "gigabytes", 1<<30 },
+ { "gigabits", 1<<27 },
+ { "gigabit", 1<<27 },
+ { "gbits", 1<<27 },
+ { "gbit", 1<<27 },
{ "tb", U64_LITERAL(1)<<40 },
{ "terabyte", U64_LITERAL(1)<<40 },
{ "terabytes", U64_LITERAL(1)<<40 },
+ { "terabits", U64_LITERAL(1)<<37 },
+ { "terabit", U64_LITERAL(1)<<37 },
+ { "tbits", U64_LITERAL(1)<<37 },
+ { "tbit", U64_LITERAL(1)<<37 },
{ NULL, 0 },
};
diff --git a/src/or/confparse.h b/src/or/confparse.h
index d82e1096c..924ee0d94 100644
--- a/src/or/confparse.h
+++ b/src/or/confparse.h
@@ -76,7 +76,7 @@ typedef int (*validate_fn_t)(void*,void*,int,char**);
/** Information on the keys, value types, key-to-struct-member mappings,
* variable descriptions, validation functions, and abbreviations for a
* configuration or storage format. */
-typedef struct {
+typedef struct config_format_t {
size_t size; /**< Size of the struct that everything gets parsed into. */
uint32_t magic; /**< Required 'magic value' to make sure we have a struct
* of the right type. */
diff --git a/src/or/connection.c b/src/or/connection.c
index aa3cc330d..8c66a170e 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -10,6 +10,7 @@
* on connections.
**/
+#define CONNECTION_PRIVATE
#include "or.h"
#include "buffers.h"
/*
@@ -33,6 +34,7 @@
#include "dns.h"
#include "dnsserv.h"
#include "entrynodes.h"
+#include "ext_orport.h"
#include "geoip.h"
#include "main.h"
#include "policies.h"
@@ -98,6 +100,7 @@ static smartlist_t *outgoing_addrs = NULL;
#define CASE_ANY_LISTENER_TYPE \
case CONN_TYPE_OR_LISTENER: \
+ case CONN_TYPE_EXT_OR_LISTENER: \
case CONN_TYPE_AP_LISTENER: \
case CONN_TYPE_DIR_LISTENER: \
case CONN_TYPE_CONTROL_LISTENER: \
@@ -129,6 +132,8 @@ conn_type_to_string(int type)
case CONN_TYPE_CPUWORKER: return "CPU worker";
case CONN_TYPE_CONTROL_LISTENER: return "Control listener";
case CONN_TYPE_CONTROL: return "Control";
+ case CONN_TYPE_EXT_OR: return "Extended OR";
+ case CONN_TYPE_EXT_OR_LISTENER: return "Extended OR listener";
default:
log_warn(LD_BUG, "unknown connection type %d", type);
tor_snprintf(buf, sizeof(buf), "unknown [%d]", type);
@@ -165,6 +170,18 @@ conn_state_to_string(int type, int state)
case OR_CONN_STATE_OPEN: return "open";
}
break;
+ case CONN_TYPE_EXT_OR:
+ switch (state) {
+ case EXT_OR_CONN_STATE_AUTH_WAIT_AUTH_TYPE:
+ return "waiting for authentication type";
+ case EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_NONCE:
+ return "waiting for client nonce";
+ case EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH:
+ return "waiting for client hash";
+ case EXT_OR_CONN_STATE_OPEN: return "open";
+ case EXT_OR_CONN_STATE_FLUSHING: return "flushing final OKAY";
+ }
+ break;
case CONN_TYPE_EXIT:
switch (state) {
case EXIT_CONN_STATE_RESOLVING: return "waiting for dest info";
@@ -229,6 +246,7 @@ connection_type_uses_bufferevent(connection_t *conn)
case CONN_TYPE_DIR:
case CONN_TYPE_CONTROL:
case CONN_TYPE_OR:
+ case CONN_TYPE_EXT_OR:
case CONN_TYPE_CPUWORKER:
return 1;
default:
@@ -259,14 +277,18 @@ dir_connection_new(int socket_family)
* Set active_circuit_pqueue_last_recalibrated to current cell_ewma tick.
*/
or_connection_t *
-or_connection_new(int socket_family)
+or_connection_new(int type, int socket_family)
{
or_connection_t *or_conn = tor_malloc_zero(sizeof(or_connection_t));
time_t now = time(NULL);
- connection_init(now, TO_CONN(or_conn), CONN_TYPE_OR, socket_family);
+ tor_assert(type == CONN_TYPE_OR || type == CONN_TYPE_EXT_OR);
+ connection_init(now, TO_CONN(or_conn), type, socket_family);
or_conn->timestamp_last_added_nonpadding = time(NULL);
+ if (type == CONN_TYPE_EXT_OR)
+ connection_or_set_ext_or_identifier(or_conn);
+
return or_conn;
}
@@ -335,7 +357,8 @@ connection_new(int type, int socket_family)
{
switch (type) {
case CONN_TYPE_OR:
- return TO_CONN(or_connection_new(socket_family));
+ case CONN_TYPE_EXT_OR:
+ return TO_CONN(or_connection_new(type, socket_family));
case CONN_TYPE_EXIT:
return TO_CONN(edge_connection_new(type, socket_family));
@@ -377,6 +400,7 @@ connection_init(time_t now, connection_t *conn, int type, int socket_family)
switch (type) {
case CONN_TYPE_OR:
+ case CONN_TYPE_EXT_OR:
conn->magic = OR_CONNECTION_MAGIC;
break;
case CONN_TYPE_EXIT:
@@ -435,7 +459,7 @@ connection_link_connections(connection_t *conn_a, connection_t *conn_b)
* necessary, close its socket if necessary, and mark the directory as dirty
* if <b>conn</b> is an OR or OP connection.
*/
-static void
+STATIC void
connection_free_(connection_t *conn)
{
void *mem;
@@ -445,6 +469,7 @@ connection_free_(connection_t *conn)
switch (conn->type) {
case CONN_TYPE_OR:
+ case CONN_TYPE_EXT_OR:
tor_assert(conn->magic == OR_CONNECTION_MAGIC);
mem = TO_OR_CONN(conn);
memlen = sizeof(or_connection_t);
@@ -575,6 +600,13 @@ connection_free_(connection_t *conn)
log_warn(LD_BUG, "called on OR conn with non-zeroed identity_digest");
connection_or_remove_from_identity_map(TO_OR_CONN(conn));
}
+ if (conn->type == CONN_TYPE_OR || conn->type == CONN_TYPE_EXT_OR) {
+ connection_or_remove_from_ext_or_id_map(TO_OR_CONN(conn));
+ tor_free(TO_OR_CONN(conn)->ext_or_conn_id);
+ tor_free(TO_OR_CONN(conn)->ext_or_auth_correct_client_hash);
+ tor_free(TO_OR_CONN(conn)->ext_or_transport);
+ }
+
#ifdef USE_BUFFEREVENTS
if (conn->type == CONN_TYPE_OR && TO_OR_CONN(conn)->bucket_cfg) {
ev_token_bucket_cfg_free(TO_OR_CONN(conn)->bucket_cfg);
@@ -638,6 +670,7 @@ connection_about_to_close_connection(connection_t *conn)
connection_dir_about_to_close(TO_DIR_CONN(conn));
break;
case CONN_TYPE_OR:
+ case CONN_TYPE_EXT_OR:
connection_or_about_to_close(TO_OR_CONN(conn));
break;
case CONN_TYPE_AP:
@@ -877,8 +910,11 @@ check_location_for_unix_socket(const or_options_t *options, const char *path)
int r = -1;
char *p = tor_strdup(path);
cpd_check_t flags = CPD_CHECK_MODE_ONLY;
- if (get_parent_directory(p)<0)
+ if (get_parent_directory(p)<0 || p[0] != '/') {
+ log_warn(LD_GENERAL, "Bad unix socket address '%s'. Tor does not support "
+ "relative paths for unix sockets.", path);
goto done;
+ }
if (options->ControlSocketsGroupWritable)
flags |= CPD_GROUP_OK;
@@ -967,7 +1003,7 @@ connection_listener_new(const struct sockaddr *listensockaddr,
log_notice(LD_NET, "Opening %s on %s",
conn_type_to_string(type), fmt_addrport(&addr, usePort));
- s = tor_open_socket(tor_addr_family(&addr),
+ s = tor_open_socket_nonblocking(tor_addr_family(&addr),
is_tcp ? SOCK_STREAM : SOCK_DGRAM,
is_tcp ? IPPROTO_TCP: IPPROTO_UDP);
if (!SOCKET_OK(s)) {
@@ -1051,7 +1087,7 @@ connection_listener_new(const struct sockaddr *listensockaddr,
strerror(errno));
goto err;
}
- s = tor_open_socket(AF_UNIX, SOCK_STREAM, 0);
+ s = tor_open_socket_nonblocking(AF_UNIX, SOCK_STREAM, 0);
if (! SOCKET_OK(s)) {
log_warn(LD_NET,"Socket creation failed: %s.", strerror(errno));
goto err;
@@ -1099,9 +1135,6 @@ connection_listener_new(const struct sockaddr *listensockaddr,
tor_assert(0);
}
- if (set_socket_nonblocking(s) == -1)
- goto err;
-
lis_conn = listener_connection_new(type, listensockaddr->sa_family);
conn = TO_CONN(lis_conn);
conn->socket_family = listensockaddr->sa_family;
@@ -1249,7 +1282,7 @@ connection_handle_listener_read(connection_t *conn, int new_type)
tor_assert((size_t)remotelen >= sizeof(struct sockaddr_in));
memset(&addrbuf, 0, sizeof(addrbuf));
- news = tor_accept_socket(conn->s,remote,&remotelen);
+ news = tor_accept_socket_nonblocking(conn->s,remote,&remotelen);
if (!SOCKET_OK(news)) { /* accept() error */
int e = tor_socket_errno(conn->s);
if (ERRNO_IS_ACCEPT_EAGAIN(e)) {
@@ -1269,10 +1302,6 @@ connection_handle_listener_read(connection_t *conn, int new_type)
(int)news,(int)conn->s);
make_socket_reuseable(news);
- if (set_socket_nonblocking(news) == -1) {
- tor_close_socket(news);
- return 0;
- }
if (options->ConstrainedSockets)
set_constrained_socket_buffers(news, (int)options->ConstrainedSockSize);
@@ -1371,6 +1400,9 @@ connection_init_accepted_conn(connection_t *conn,
connection_start_reading(conn);
switch (conn->type) {
+ case CONN_TYPE_EXT_OR:
+ /* Initiate Extended ORPort authentication. */
+ return connection_ext_or_start_auth(TO_OR_CONN(conn));
case CONN_TYPE_OR:
control_event_or_conn_status(TO_OR_CONN(conn), OR_CONN_EVENT_NEW, 0);
rv = connection_tls_start_handshake(TO_OR_CONN(conn), 1);
@@ -1464,7 +1496,7 @@ connection_connect(connection_t *conn, const char *address,
return -1;
}
- s = tor_open_socket(protocol_family,SOCK_STREAM,IPPROTO_TCP);
+ s = tor_open_socket_nonblocking(protocol_family,SOCK_STREAM,IPPROTO_TCP);
if (! SOCKET_OK(s)) {
*socket_error = tor_socket_errno(-1);
log_warn(LD_NET,"Error creating network socket: %s",
@@ -1506,12 +1538,6 @@ connection_connect(connection_t *conn, const char *address,
}
}
- if (set_socket_nonblocking(s) == -1) {
- *socket_error = tor_socket_errno(s);
- tor_close_socket(s);
- return -1;
- }
-
if (options->ConstrainedSockets)
set_constrained_socket_buffers(s, (int)options->ConstrainedSockSize);
@@ -2883,6 +2909,8 @@ connection_handle_read_impl(connection_t *conn)
switch (conn->type) {
case CONN_TYPE_OR_LISTENER:
return connection_handle_listener_read(conn, CONN_TYPE_OR);
+ case CONN_TYPE_EXT_OR_LISTENER:
+ return connection_handle_listener_read(conn, CONN_TYPE_EXT_OR);
case CONN_TYPE_AP_LISTENER:
case CONN_TYPE_AP_TRANS_LISTENER:
case CONN_TYPE_AP_NATD_LISTENER:
@@ -3673,9 +3701,9 @@ connection_flush(connection_t *conn)
* it all, so we don't end up with many megabytes of controller info queued at
* once.
*/
-void
-connection_write_to_buf_impl_(const char *string, size_t len,
- connection_t *conn, int zlib)
+MOCK_IMPL(void,
+connection_write_to_buf_impl_,(const char *string, size_t len,
+ connection_t *conn, int zlib))
{
/* XXXX This function really needs to return -1 on failure. */
int r;
@@ -3915,6 +3943,7 @@ int
connection_is_listener(connection_t *conn)
{
if (conn->type == CONN_TYPE_OR_LISTENER ||
+ conn->type == CONN_TYPE_EXT_OR_LISTENER ||
conn->type == CONN_TYPE_AP_LISTENER ||
conn->type == CONN_TYPE_AP_TRANS_LISTENER ||
conn->type == CONN_TYPE_AP_DNS_LISTENER ||
@@ -3937,6 +3966,7 @@ connection_state_is_open(connection_t *conn)
return 0;
if ((conn->type == CONN_TYPE_OR && conn->state == OR_CONN_STATE_OPEN) ||
+ (conn->type == CONN_TYPE_EXT_OR) ||
(conn->type == CONN_TYPE_AP && conn->state == AP_CONN_STATE_OPEN) ||
(conn->type == CONN_TYPE_EXIT && conn->state == EXIT_CONN_STATE_OPEN) ||
(conn->type == CONN_TYPE_CONTROL &&
@@ -4106,6 +4136,8 @@ connection_process_inbuf(connection_t *conn, int package_partial)
switch (conn->type) {
case CONN_TYPE_OR:
return connection_or_process_inbuf(TO_OR_CONN(conn));
+ case CONN_TYPE_EXT_OR:
+ return connection_ext_or_process_inbuf(TO_OR_CONN(conn));
case CONN_TYPE_EXIT:
case CONN_TYPE_AP:
return connection_edge_process_inbuf(TO_EDGE_CONN(conn),
@@ -4166,6 +4198,8 @@ connection_finished_flushing(connection_t *conn)
switch (conn->type) {
case CONN_TYPE_OR:
return connection_or_finished_flushing(TO_OR_CONN(conn));
+ case CONN_TYPE_EXT_OR:
+ return connection_ext_or_finished_flushing(TO_OR_CONN(conn));
case CONN_TYPE_AP:
case CONN_TYPE_EXIT:
return connection_edge_finished_flushing(TO_EDGE_CONN(conn));
@@ -4221,6 +4255,7 @@ connection_reached_eof(connection_t *conn)
{
switch (conn->type) {
case CONN_TYPE_OR:
+ case CONN_TYPE_EXT_OR:
return connection_or_reached_eof(TO_OR_CONN(conn));
case CONN_TYPE_AP:
case CONN_TYPE_EXIT:
@@ -4307,6 +4342,7 @@ assert_connection_ok(connection_t *conn, time_t now)
switch (conn->type) {
case CONN_TYPE_OR:
+ case CONN_TYPE_EXT_OR:
tor_assert(conn->magic == OR_CONNECTION_MAGIC);
break;
case CONN_TYPE_AP:
@@ -4412,6 +4448,10 @@ assert_connection_ok(connection_t *conn, time_t now)
tor_assert(conn->state >= OR_CONN_STATE_MIN_);
tor_assert(conn->state <= OR_CONN_STATE_MAX_);
break;
+ case CONN_TYPE_EXT_OR:
+ tor_assert(conn->state >= EXT_OR_CONN_STATE_MIN_);
+ tor_assert(conn->state <= EXT_OR_CONN_STATE_MAX_);
+ break;
case CONN_TYPE_EXIT:
tor_assert(conn->state >= EXIT_CONN_STATE_MIN_);
tor_assert(conn->state <= EXIT_CONN_STATE_MAX_);
@@ -4544,6 +4584,7 @@ connection_free_all(void)
/* Unlink everything from the identity map. */
connection_or_clear_identity_map();
+ connection_or_clear_ext_or_id_map();
/* Clear out our list of broken connections */
clear_broken_connection_map(0);
diff --git a/src/or/connection.h b/src/or/connection.h
index 3e656ec06..0454ac2f3 100644
--- a/src/or/connection.h
+++ b/src/or/connection.h
@@ -19,7 +19,7 @@ const char *conn_type_to_string(int type);
const char *conn_state_to_string(int type, int state);
dir_connection_t *dir_connection_new(int socket_family);
-or_connection_t *or_connection_new(int socket_family);
+or_connection_t *or_connection_new(int type, int socket_family);
edge_connection_t *edge_connection_new(int type, int socket_family);
entry_connection_t *entry_connection_new(int type, int socket_family);
control_connection_t *control_connection_new(int socket_family);
@@ -130,8 +130,8 @@ int connection_outbuf_too_full(connection_t *conn);
int connection_handle_write(connection_t *conn, int force);
int connection_flush(connection_t *conn);
-void connection_write_to_buf_impl_(const char *string, size_t len,
- connection_t *conn, int zlib);
+MOCK_DECL(void, connection_write_to_buf_impl_,
+ (const char *string, size_t len, connection_t *conn, int zlib));
/* DOCDOC connection_write_to_buf */
static void connection_write_to_buf(const char *string, size_t len,
connection_t *conn);
@@ -214,5 +214,9 @@ void connection_enable_rate_limiting(connection_t *conn);
#define connection_type_uses_bufferevent(c) (0)
#endif
+#ifdef CONNECTION_PRIVATE
+STATIC void connection_free_(connection_t *conn);
+#endif
+
#endif
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index bb7ffb9a4..33585a094 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -407,7 +407,7 @@ connection_edge_finished_flushing(edge_connection_t *conn)
* that the name resolution that led us to <b>addr</b> will be valid for
* <b>ttl</b> seconds. Return -1 on error, or the number of bytes used on
* success. */
-/* private */int
+STATIC int
connected_cell_format_payload(uint8_t *payload_out,
const tor_addr_t *addr,
uint32_t ttl)
@@ -2265,7 +2265,7 @@ connection_ap_handshake_socks_reply(entry_connection_t *conn, char *reply,
* Return -1 in the case where want to send a RELAY_END cell, and < -1 when
* we don't.
**/
-/* static */ int
+STATIC int
begin_cell_parse(const cell_t *cell, begin_cell_t *bcell,
uint8_t *end_reason_out)
{
diff --git a/src/or/connection_edge.h b/src/or/connection_edge.h
index ea284cbcf..e3a95ad9e 100644
--- a/src/or/connection_edge.h
+++ b/src/or/connection_edge.h
@@ -12,6 +12,8 @@
#ifndef TOR_CONNECTION_EDGE_H
#define TOR_CONNECTION_EDGE_H
+#include "testsupport.h"
+
#define connection_mark_unattached_ap(conn, endreason) \
connection_mark_unattached_ap_((conn), (endreason), __LINE__, SHORT_FILE__)
@@ -130,9 +132,9 @@ typedef struct begin_cell_t {
unsigned is_begindir : 1;
} begin_cell_t;
-int begin_cell_parse(const cell_t *cell, begin_cell_t *bcell,
+STATIC int begin_cell_parse(const cell_t *cell, begin_cell_t *bcell,
uint8_t *end_reason_out);
-int connected_cell_format_payload(uint8_t *payload_out,
+STATIC int connected_cell_format_payload(uint8_t *payload_out,
const tor_addr_t *addr,
uint32_t ttl);
#endif
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index 361636350..31fd6d673 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -37,7 +37,7 @@
#include "rephist.h"
#include "router.h"
#include "routerlist.h"
-
+#include "ext_orport.h"
#ifdef USE_BUFFEREVENTS
#include <event2/bufferevent_ssl.h>
#endif
@@ -75,6 +75,10 @@ static void connection_or_handle_event_cb(struct bufferevent *bufev,
* they form a linked list, with next_with_same_id as the next pointer. */
static digestmap_t *orconn_identity_map = NULL;
+/** Global map between Extended ORPort identifiers and OR
+ * connections. */
+static digestmap_t *orconn_ext_or_id_map = NULL;
+
/** If conn is listed in orconn_identity_map, remove it, and clear
* conn->identity_digest. Otherwise do nothing. */
void
@@ -174,6 +178,71 @@ connection_or_set_identity_digest(or_connection_t *conn, const char *digest)
#endif
}
+/** Remove the Extended ORPort identifier of <b>conn</b> from the
+ * global identifier list. Also, clear the identifier from the
+ * connection itself. */
+void
+connection_or_remove_from_ext_or_id_map(or_connection_t *conn)
+{
+ or_connection_t *tmp;
+ if (!orconn_ext_or_id_map)
+ return;
+ if (!conn->ext_or_conn_id)
+ return;
+
+ tmp = digestmap_remove(orconn_ext_or_id_map, conn->ext_or_conn_id);
+ if (!tor_digest_is_zero(conn->ext_or_conn_id))
+ tor_assert(tmp == conn);
+
+ memset(conn->ext_or_conn_id, 0, EXT_OR_CONN_ID_LEN);
+}
+
+/** Return the connection whose ext_or_id is <b>id</b>. Return NULL if no such
+ * connection is found. */
+or_connection_t *
+connection_or_get_by_ext_or_id(const char *id)
+{
+ if (!orconn_ext_or_id_map)
+ return NULL;
+ return digestmap_get(orconn_ext_or_id_map, id);
+}
+
+/** Deallocate the global Extended ORPort identifier list */
+void
+connection_or_clear_ext_or_id_map(void)
+{
+ digestmap_free(orconn_ext_or_id_map, NULL);
+ orconn_ext_or_id_map = NULL;
+}
+
+/** Creates an Extended ORPort identifier for <b>conn<b/> and deposits
+ * it into the global list of identifiers. */
+void
+connection_or_set_ext_or_identifier(or_connection_t *conn)
+{
+ char random_id[EXT_OR_CONN_ID_LEN];
+ or_connection_t *tmp;
+
+ if (!orconn_ext_or_id_map)
+ orconn_ext_or_id_map = digestmap_new();
+
+ /* Remove any previous identifiers: */
+ if (conn->ext_or_conn_id && !tor_digest_is_zero(conn->ext_or_conn_id))
+ connection_or_remove_from_ext_or_id_map(conn);
+
+ do {
+ crypto_rand(random_id, sizeof(random_id));
+ } while (digestmap_get(orconn_ext_or_id_map, random_id));
+
+ if (!conn->ext_or_conn_id)
+ conn->ext_or_conn_id = tor_malloc_zero(EXT_OR_CONN_ID_LEN);
+
+ memcpy(conn->ext_or_conn_id, random_id, EXT_OR_CONN_ID_LEN);
+
+ tmp = digestmap_set(orconn_ext_or_id_map, random_id, conn);
+ tor_assert(!tmp);
+}
+
/**************************************************************/
/** Map from a string describing what a non-open OR connection was doing when
@@ -228,7 +297,7 @@ connection_or_get_state_description(or_connection_t *orconn,
const char *conn_state;
char tls_state[256];
- tor_assert(conn->type == CONN_TYPE_OR);
+ tor_assert(conn->type == CONN_TYPE_OR || conn->type == CONN_TYPE_EXT_OR);
conn_state = conn_state_to_string(conn->type, conn->state);
tor_tls_get_state_description(orconn->tls, tls_state, sizeof(tls_state));
@@ -1077,7 +1146,7 @@ connection_or_connect(const tor_addr_t *_addr, uint16_t port,
return NULL;
}
- conn = or_connection_new(tor_addr_family(&addr));
+ conn = or_connection_new(CONN_TYPE_OR, tor_addr_family(&addr));
/*
* Set up conn so it's got all the data we need to remember for channels
@@ -1212,8 +1281,8 @@ connection_or_close_for_error(or_connection_t *orconn, int flush)
*
* Return -1 if <b>conn</b> is broken, else return 0.
*/
-int
-connection_tls_start_handshake(or_connection_t *conn, int receiving)
+MOCK_IMPL(int,
+connection_tls_start_handshake,(or_connection_t *conn, int receiving))
{
channel_listener_t *chan_listener;
channel_t *chan;
@@ -1470,7 +1539,8 @@ connection_or_handle_event_cb(struct bufferevent *bufev, short event,
int
connection_or_nonopen_was_started_here(or_connection_t *conn)
{
- tor_assert(conn->base_.type == CONN_TYPE_OR);
+ tor_assert(conn->base_.type == CONN_TYPE_OR ||
+ conn->base_.type == CONN_TYPE_EXT_OR);
if (!conn->tls)
return 1; /* it's still in proxy states or something */
if (conn->handshake_state)
diff --git a/src/or/connection_or.h b/src/or/connection_or.h
index 85e68f1a3..8d9302893 100644
--- a/src/or/connection_or.h
+++ b/src/or/connection_or.h
@@ -45,7 +45,8 @@ void connection_or_close_for_error(or_connection_t *orconn, int flush);
void connection_or_report_broken_states(int severity, int domain);
-int connection_tls_start_handshake(or_connection_t *conn, int receiving);
+MOCK_DECL(int,connection_tls_start_handshake,(or_connection_t *conn,
+ int receiving));
int connection_tls_continue_handshake(or_connection_t *conn);
int connection_init_or_handshake_state(or_connection_t *conn,
diff --git a/src/or/control.c b/src/or/control.c
index a4c674f34..d624d2879 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -115,7 +115,7 @@ static int authentication_cookie_is_set = 0;
/** If authentication_cookie_is_set, a secret cookie that we've stored to disk
* and which we're using to authenticate controllers. (If the controller can
* read it off disk, it has permission to connect.) */
-static char authentication_cookie[AUTHENTICATION_COOKIE_LEN];
+static uint8_t *authentication_cookie = NULL;
#define SAFECOOKIE_SERVER_TO_CONTROLLER_CONSTANT \
"Tor safe cookie authentication server-to-controller hash"
@@ -334,7 +334,7 @@ connection_write_str_to_buf(const char *s, control_connection_t *conn)
* the end. Replace all LF characters sequences with CRLF. Return the number
* of bytes in *<b>out</b>.
*/
-/* static */ size_t
+STATIC size_t
write_escaped_data(const char *data, size_t len, char **out)
{
size_t sz_out = len+8;
@@ -382,7 +382,7 @@ write_escaped_data(const char *data, size_t len, char **out)
* that appears at the start of a line, and replacing all CRLF sequences
* with LF. Return the number of
* bytes in *<b>out</b>. */
-/* static */ size_t
+STATIC size_t
read_escaped_data(const char *data, size_t len, char **out)
{
char *outp;
@@ -4446,44 +4446,27 @@ get_cookie_file(void)
}
}
-/** Choose a random authentication cookie and write it to disk.
- * Anybody who can read the cookie from disk will be considered
- * authorized to use the control connection. Return -1 if we can't
- * write the file, or 0 on success. */
+/* Initialize the cookie-based authentication system of the
+ * ControlPort. If <b>enabled</b> is 0, then disable the cookie
+ * authentication system. */
int
-init_cookie_authentication(int enabled)
+init_control_cookie_authentication(int enabled)
{
- char *fname;
+ char *fname = NULL;
+ int retval;
+
if (!enabled) {
authentication_cookie_is_set = 0;
return 0;
}
- /* We don't want to generate a new cookie every time we call
- * options_act(). One should be enough. */
- if (authentication_cookie_is_set)
- return 0; /* all set */
-
fname = get_cookie_file();
- crypto_rand(authentication_cookie, AUTHENTICATION_COOKIE_LEN);
- authentication_cookie_is_set = 1;
- if (write_bytes_to_file(fname, authentication_cookie,
- AUTHENTICATION_COOKIE_LEN, 1)) {
- log_warn(LD_FS,"Error writing authentication cookie to %s.",
- escaped(fname));
- tor_free(fname);
- return -1;
- }
-#ifndef _WIN32
- if (get_options()->CookieAuthFileGroupReadable) {
- if (chmod(fname, 0640)) {
- log_warn(LD_FS,"Unable to make %s group-readable.", escaped(fname));
- }
- }
-#endif
-
+ retval = init_cookie_authentication(fname, "", /* no header */
+ AUTHENTICATION_COOKIE_LEN,
+ &authentication_cookie,
+ &authentication_cookie_is_set);
tor_free(fname);
- return 0;
+ return retval;
}
/** A copy of the process specifier of Tor's owning controller, or
@@ -4699,8 +4682,8 @@ control_event_bootstrap(bootstrap_status_t status, int progress)
* that indicates a problem. <b>warn</b> gives a hint as to why, and
* <b>reason</b> provides an "or_conn_end_reason" tag.
*/
-void
-control_event_bootstrap_problem(const char *warn, int reason)
+MOCK_IMPL(void,
+control_event_bootstrap_problem, (const char *warn, int reason))
{
int status = bootstrap_percent;
const char *tag, *summary;
@@ -4767,3 +4750,11 @@ control_event_clients_seen(const char *controller_str)
"650 CLIENTS_SEEN %s\r\n", controller_str);
}
+/** Free any leftover allocated memory of the control.c subsystem. */
+void
+control_free_all(void)
+{
+ if (authentication_cookie) /* Free the auth cookie */
+ tor_free(authentication_cookie);
+}
+
diff --git a/src/or/control.h b/src/or/control.h
index 61062da2c..be9476ea3 100644
--- a/src/or/control.h
+++ b/src/or/control.h
@@ -77,7 +77,7 @@ int control_event_buildtimeout_set(const circuit_build_times_t *cbt,
buildtimeout_set_event_t type);
int control_event_signal(uintptr_t signal);
-int init_cookie_authentication(int enabled);
+int init_control_cookie_authentication(int enabled);
smartlist_t *decode_hashed_passwords(config_line_t *passwords);
void disable_control_logging(void);
void enable_control_logging(void);
@@ -85,14 +85,16 @@ void enable_control_logging(void);
void monitor_owning_controller_process(const char *process_spec);
void control_event_bootstrap(bootstrap_status_t status, int progress);
-void control_event_bootstrap_problem(const char *warn, int reason);
+MOCK_DECL(void, control_event_bootstrap_problem,(const char *warn,
+ int reason));
void control_event_clients_seen(const char *controller_str);
+void control_free_all(void);
#ifdef CONTROL_PRIVATE
/* Used only by control.c and test.c */
-size_t write_escaped_data(const char *data, size_t len, char **out);
-size_t read_escaped_data(const char *data, size_t len, char **out);
+STATIC size_t write_escaped_data(const char *data, size_t len, char **out);
+STATIC size_t read_escaped_data(const char *data, size_t len, char **out);
#endif
#endif
diff --git a/src/or/directory.c b/src/or/directory.c
index 88d671779..97305ae2a 100644
--- a/src/or/directory.c
+++ b/src/or/directory.c
@@ -2966,7 +2966,9 @@ directory_handle_command_get(dir_connection_t *conn, const char *headers,
tor_addr_t addr;
if (tor_inet_aton((TO_CONN(conn))->address, &in)) {
tor_addr_from_ipv4h(&addr, ntohl(in.s_addr));
- geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS, &addr, time(NULL));
+ geoip_note_client_seen(GEOIP_CLIENT_NETWORKSTATUS,
+ &addr, NULL,
+ time(NULL));
geoip_note_ns_response(GEOIP_SUCCESS);
/* Note that a request for a network status has started, so that we
* can measure the download time later on. */
diff --git a/src/or/dirserv.c b/src/or/dirserv.c
index 97fe06884..3243ac47c 100644
--- a/src/or/dirserv.c
+++ b/src/or/dirserv.c
@@ -2082,7 +2082,7 @@ static digestmap_t *mbw_cache = NULL;
/** Store a measured bandwidth cache entry when reading the measured
* bandwidths file. */
-void
+STATIC void
dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line,
time_t as_of)
{
@@ -2112,7 +2112,7 @@ dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line,
}
/** Clear and free the measured bandwidth cache */
-void
+STATIC void
dirserv_clear_measured_bw_cache(void)
{
if (mbw_cache) {
@@ -2123,7 +2123,7 @@ dirserv_clear_measured_bw_cache(void)
}
/** Scan the measured bandwidth cache and remove expired entries */
-void
+STATIC void
dirserv_expire_measured_bw_cache(time_t now)
{
@@ -2145,7 +2145,7 @@ dirserv_expire_measured_bw_cache(time_t now)
}
/** Get the current size of the measured bandwidth cache */
-int
+STATIC int
dirserv_get_measured_bw_cache_size(void)
{
if (mbw_cache) return digestmap_size(mbw_cache);
@@ -2155,7 +2155,7 @@ dirserv_get_measured_bw_cache_size(void)
/** Query the cache by identity digest, return value indicates whether
* we found it. The bw_out and as_of_out pointers receive the cached
* bandwidth value and the time it was cached if not NULL. */
-int
+STATIC int
dirserv_query_measured_bw_cache_kb(const char *node_id, long *bw_kb_out,
time_t *as_of_out)
{
@@ -2176,7 +2176,7 @@ dirserv_query_measured_bw_cache_kb(const char *node_id, long *bw_kb_out,
}
/** Predicate wrapper for dirserv_query_measured_bw_cache() */
-int
+STATIC int
dirserv_has_measured_bw(const char *node_id)
{
return dirserv_query_measured_bw_cache_kb(node_id, NULL, NULL);
@@ -2754,7 +2754,7 @@ clear_status_flags_on_sybil(routerstatus_t *rs)
* into a measured_bw_line_t output structure. Returns -1 on failure
* or 0 on success.
*/
-int
+STATIC int
measured_bw_line_parse(measured_bw_line_t *out, const char *orig_line)
{
char *line = tor_strdup(orig_line);
@@ -2835,7 +2835,7 @@ measured_bw_line_parse(measured_bw_line_t *out, const char *orig_line)
* of bandwidth statuses. Returns true if a line is found,
* false otherwise.
*/
-int
+STATIC int
measured_bw_line_apply(measured_bw_line_t *parsed_line,
smartlist_t *routerstatuses)
{
@@ -3168,7 +3168,7 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key,
/** For v2 authoritative directories only: Replace the contents of
* <b>the_v2_networkstatus</b> with a newly generated network status
* object. */
-cached_dir_t *
+STATIC cached_dir_t *
generate_v2_networkstatus_opinion(void)
{
cached_dir_t *r = NULL;
diff --git a/src/or/dirserv.h b/src/or/dirserv.h
index f9d36d760..7221fc995 100644
--- a/src/or/dirserv.h
+++ b/src/or/dirserv.h
@@ -12,6 +12,8 @@
#ifndef TOR_DIRSERV_H
#define TOR_DIRSERV_H
+#include "testsupport.h"
+
/** What fraction (1 over this number) of the relay ID space do we
* (as a directory authority) launch connections to at each reachability
* test? */
@@ -119,20 +121,21 @@ cached_dir_t *new_cached_dir(char *s, time_t published);
/* Put the MAX_MEASUREMENT_AGE #define here so unit tests can see it */
#define MAX_MEASUREMENT_AGE (3*24*60*60) /* 3 days */
-int measured_bw_line_parse(measured_bw_line_t *out, const char *line);
+STATIC int measured_bw_line_parse(measured_bw_line_t *out, const char *line);
-int measured_bw_line_apply(measured_bw_line_t *parsed_line,
+STATIC int measured_bw_line_apply(measured_bw_line_t *parsed_line,
smartlist_t *routerstatuses);
-void dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line,
+STATIC void dirserv_cache_measured_bw(const measured_bw_line_t *parsed_line,
time_t as_of);
-void dirserv_clear_measured_bw_cache(void);
-void dirserv_expire_measured_bw_cache(time_t now);
-int dirserv_get_measured_bw_cache_size(void);
-int dirserv_query_measured_bw_cache_kb(const char *node_id, long *bw_out,
- time_t *as_of_out);
-int dirserv_has_measured_bw(const char *node_id);
-cached_dir_t *generate_v2_networkstatus_opinion(void);
+STATIC void dirserv_clear_measured_bw_cache(void);
+STATIC void dirserv_expire_measured_bw_cache(time_t now);
+STATIC int dirserv_get_measured_bw_cache_size(void);
+STATIC int dirserv_query_measured_bw_cache_kb(const char *node_id,
+ long *bw_out,
+ time_t *as_of_out);
+STATIC int dirserv_has_measured_bw(const char *node_id);
+STATIC cached_dir_t *generate_v2_networkstatus_opinion(void);
#endif
int dirserv_read_measured_bandwidths(const char *from_file,
diff --git a/src/or/dirvote.c b/src/or/dirvote.c
index 4f0ab6833..12ceba854 100644
--- a/src/or/dirvote.c
+++ b/src/or/dirvote.c
@@ -60,7 +60,7 @@ static char *make_consensus_method_list(int low, int high, const char *sep);
/** Return a new string containing the string representation of the vote in
* <b>v3_ns</b>, signed with our v3 signing key <b>private_signing_key</b>.
* For v3 authorities. */
-char *
+STATIC char *
format_networkstatus_vote(crypto_pk_t *private_signing_key,
networkstatus_t *v3_ns)
{
@@ -587,7 +587,7 @@ compute_consensus_versions_list(smartlist_t *lst, int n_versioning)
/** Helper: given a list of valid networkstatus_t, return a new string
* containing the contents of the consensus network parameter set.
*/
-/* private */ char *
+STATIC char *
dirvote_compute_params(smartlist_t *votes, int method, int total_authorities)
{
int i;
@@ -1590,10 +1590,19 @@ networkstatus_compute_consensus(smartlist_t *votes,
unnamed_flag[i] = named_flag[i] = -1;
chosen_named_idx = smartlist_string_pos(flags, "Named");
- /* Build the flag index. */
+ /* Build the flag indexes. Note that no vote can have more than 64 members
+ * for known_flags, so no value will be greater than 63, so it's safe to
+ * do U64_LITERAL(1) << index on these values. But note also that
+ * named_flag and unnamed_flag are initialized to -1, so we need to check
+ * that they're actually set before doing U64_LITERAL(1) << index with
+ * them.*/
SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) {
flag_map[v_sl_idx] = tor_malloc_zero(
sizeof(int)*smartlist_len(v->known_flags));
+ if (smartlist_len(v->known_flags) > MAX_KNOWN_FLAGS_IN_VOTE) {
+ log_warn(LD_BUG, "Somehow, a vote has %d entries in known_flags",
+ smartlist_len(v->known_flags));
+ }
SMARTLIST_FOREACH_BEGIN(v->known_flags, const char *, fl) {
int p = smartlist_string_pos(flags, fl);
tor_assert(p >= 0);
@@ -1727,7 +1736,8 @@ networkstatus_compute_consensus(smartlist_t *votes,
if (rs->flags & (U64_LITERAL(1) << i))
++flag_counts[flag_map[v_sl_idx][i]];
}
- if (rs->flags & (U64_LITERAL(1) << named_flag[v_sl_idx])) {
+ if (named_flag[v_sl_idx] >= 0 &&
+ (rs->flags & (U64_LITERAL(1) << named_flag[v_sl_idx]))) {
if (chosen_name && strcmp(chosen_name, rs->status.nickname)) {
log_notice(LD_DIR, "Conflict on naming for router: %s vs %s",
chosen_name, rs->status.nickname);
diff --git a/src/or/dirvote.h b/src/or/dirvote.h
index a3e6cc0d6..3a4951a95 100644
--- a/src/or/dirvote.h
+++ b/src/or/dirvote.h
@@ -12,6 +12,8 @@
#ifndef TOR_DIRVOTE_H
#define TOR_DIRVOTE_H
+#include "testsupport.h"
+
/** Lowest allowable value for VoteSeconds. */
#define MIN_VOTE_SECONDS 2
/** Lowest allowable value for DistSeconds. */
@@ -136,9 +138,9 @@ document_signature_t *voter_get_sig_by_algorithm(
digest_algorithm_t alg);
#ifdef DIRVOTE_PRIVATE
-char *format_networkstatus_vote(crypto_pk_t *private_key,
+STATIC char *format_networkstatus_vote(crypto_pk_t *private_key,
networkstatus_t *v3_ns);
-char *dirvote_compute_params(smartlist_t *votes, int method,
+STATIC char *dirvote_compute_params(smartlist_t *votes, int method,
int total_authorities);
#endif
diff --git a/src/or/dns.c b/src/or/dns.c
index edcf92e5b..f2b7eecc3 100644
--- a/src/or/dns.c
+++ b/src/or/dns.c
@@ -437,8 +437,8 @@ cached_resolve_add_answer(cached_resolve_t *resolve,
if (resolve->res_status_ipv4 != RES_STATUS_INFLIGHT)
return;
- if (dns_result == DNS_ERR_NONE && answer_addr) {
- tor_assert(tor_addr_family(answer_addr) == AF_INET);
+ if (dns_result == DNS_ERR_NONE && answer_addr &&
+ tor_addr_family(answer_addr) == AF_INET) {
resolve->result_ipv4.addr_ipv4 = tor_addr_to_ipv4h(answer_addr);
resolve->res_status_ipv4 = RES_STATUS_DONE_OK;
} else {
@@ -450,8 +450,8 @@ cached_resolve_add_answer(cached_resolve_t *resolve,
if (resolve->res_status_ipv6 != RES_STATUS_INFLIGHT)
return;
- if (dns_result == DNS_ERR_NONE && answer_addr) {
- tor_assert(tor_addr_family(answer_addr) == AF_INET6);
+ if (dns_result == DNS_ERR_NONE && answer_addr &&
+ tor_addr_family(answer_addr) == AF_INET6) {
memcpy(&resolve->result_ipv6.addr_ipv6,
tor_addr_to_in6(answer_addr),
sizeof(struct in6_addr));
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index 70f7c878e..cadc70ec7 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -419,14 +419,24 @@ add_an_entry_guard(const node_t *chosen, int reset_status, int prepend,
return node;
}
+/** Choose how many entry guards or directory guards we'll use. If
+ * <b>for_directory</b> is true, we return how many directory guards to
+ * use; else we return how many entry guards to use. */
+static int
+decide_num_guards(const or_options_t *options, int for_directory)
+{
+ if (for_directory && options->NumDirectoryGuards != 0)
+ return options->NumDirectoryGuards;
+ return options->NumEntryGuards;
+}
+
/** If the use of entry guards is configured, choose more entry guards
* until we have enough in the list. */
static void
pick_entry_guards(const or_options_t *options, int for_directory)
{
int changed = 0;
- const int num_needed = for_directory ? options->NumDirectoryGuards :
- options->NumEntryGuards;
+ const int num_needed = decide_num_guards(options, for_directory);
tor_assert(entry_guards);
@@ -966,8 +976,7 @@ choose_random_entry_impl(cpath_build_state_t *state, int for_directory,
int need_capacity = state ? state->need_capacity : 0;
int preferred_min, consider_exit_family = 0;
int need_descriptor = !for_directory;
- const int num_needed = for_directory ? options->NumDirectoryGuards :
- options->NumEntryGuards;
+ const int num_needed = decide_num_guards(options, for_directory);
if (chosen_exit) {
nodelist_add_node_and_family(exit_family, chosen_exit);
diff --git a/src/or/ext_orport.c b/src/or/ext_orport.c
new file mode 100644
index 000000000..d5a0fa1ee
--- /dev/null
+++ b/src/or/ext_orport.c
@@ -0,0 +1,648 @@
+/* Copyright (c) 2012, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+/**
+ * \file ext_orport.c
+ * \brief Code implementing the Extended ORPort.
+*/
+
+#define EXT_ORPORT_PRIVATE
+#include "or.h"
+#include "connection.h"
+#include "connection_or.h"
+#include "ext_orport.h"
+#include "control.h"
+#include "config.h"
+#include "util.h"
+#include "main.h"
+
+/** Allocate and return a structure capable of holding an Extended
+ * ORPort message of body length <b>len</b>. */
+ext_or_cmd_t *
+ext_or_cmd_new(uint16_t len)
+{
+ size_t size = STRUCT_OFFSET(ext_or_cmd_t, body) + len;
+ ext_or_cmd_t *cmd = tor_malloc(size);
+ cmd->len = len;
+ return cmd;
+}
+
+/** Deallocate the Extended ORPort message in <b>cmd</b>. */
+void
+ext_or_cmd_free(ext_or_cmd_t *cmd)
+{
+ tor_free(cmd);
+}
+
+/** Get an Extended ORPort message from <b>conn</b>, and place it in
+ * <b>out</b>. Return -1 on fail, 0 if we need more data, and 1 if we
+ * successfully extracted an Extended ORPort command from the
+ * buffer. */
+static int
+connection_fetch_ext_or_cmd_from_buf(connection_t *conn, ext_or_cmd_t **out)
+{
+ IF_HAS_BUFFEREVENT(conn, {
+ struct evbuffer *input = bufferevent_get_input(conn->bufev);
+ return fetch_ext_or_command_from_evbuffer(input, out);
+ }) ELSE_IF_NO_BUFFEREVENT {
+ return fetch_ext_or_command_from_buf(conn->inbuf, out);
+ }
+}
+
+/** Write an Extended ORPort message to <b>conn</b>. Use
+ * <b>command</b> as the command type, <b>bodylen</b> as the body
+ * length, and <b>body</b>, if it's present, as the body of the
+ * message. */
+STATIC int
+connection_write_ext_or_command(connection_t *conn,
+ uint16_t command,
+ const char *body,
+ size_t bodylen)
+{
+ char header[4];
+ if (bodylen > UINT16_MAX)
+ return -1;
+ set_uint16(header, htons(command));
+ set_uint16(header+2, htons(bodylen));
+ connection_write_to_buf(header, 4, conn);
+ if (bodylen) {
+ tor_assert(body);
+ connection_write_to_buf(body, bodylen, conn);
+ }
+ return 0;
+}
+
+/** Transition from an Extended ORPort which accepts Extended ORPort
+ * messages, to an Extended ORport which accepts OR traffic. */
+static void
+connection_ext_or_transition(or_connection_t *conn)
+{
+ tor_assert(conn->base_.type == CONN_TYPE_EXT_OR);
+
+ conn->base_.type = CONN_TYPE_OR;
+ TO_CONN(conn)->state = 0; // set the state to a neutral value
+ control_event_or_conn_status(conn, OR_CONN_EVENT_NEW, 0);
+ connection_tls_start_handshake(conn, 1);
+}
+
+/** Length of authentication cookie. */
+#define EXT_OR_PORT_AUTH_COOKIE_LEN 32
+/** Length of the header of the cookie file. */
+#define EXT_OR_PORT_AUTH_COOKIE_HEADER_LEN 32
+/** Static cookie file header. */
+#define EXT_OR_PORT_AUTH_COOKIE_HEADER "! Extended ORPort Auth Cookie !\x0a"
+/** Length of safe-cookie protocol hashes. */
+#define EXT_OR_PORT_AUTH_HASH_LEN DIGEST256_LEN
+/** Length of safe-cookie protocol nonces. */
+#define EXT_OR_PORT_AUTH_NONCE_LEN 32
+/** Safe-cookie protocol constants. */
+#define EXT_OR_PORT_AUTH_SERVER_TO_CLIENT_CONST \
+ "ExtORPort authentication server-to-client hash"
+#define EXT_OR_PORT_AUTH_CLIENT_TO_SERVER_CONST \
+ "ExtORPort authentication client-to-server hash"
+
+/* Code to indicate cookie authentication */
+#define EXT_OR_AUTHTYPE_SAFECOOKIE 0x01
+
+/** If true, we've set ext_or_auth_cookie to a secret code and stored
+ * it to disk. */
+STATIC int ext_or_auth_cookie_is_set = 0;
+/** If ext_or_auth_cookie_is_set, a secret cookie that we've stored to disk
+ * and which we're using to authenticate controllers. (If the controller can
+ * read it off disk, it has permission to connect.) */
+STATIC uint8_t *ext_or_auth_cookie = NULL;
+
+/** Helper: Return a newly allocated string containing a path to the
+ * file where we store our authentication cookie. */
+char *
+get_ext_or_auth_cookie_file_name(void)
+{
+ const or_options_t *options = get_options();
+ if (options->ExtORPortCookieAuthFile &&
+ strlen(options->ExtORPortCookieAuthFile)) {
+ return tor_strdup(options->ExtORPortCookieAuthFile);
+ } else {
+ return get_datadir_fname("extended_orport_auth_cookie");
+ }
+}
+
+/* Initialize the cookie-based authentication system of the
+ * Extended ORPort. If <b>is_enabled</b> is 0, then disable the cookie
+ * authentication system. */
+int
+init_ext_or_cookie_authentication(int is_enabled)
+{
+ char *fname = NULL;
+ int retval;
+
+ if (!is_enabled) {
+ ext_or_auth_cookie_is_set = 0;
+ return 0;
+ }
+
+ fname = get_ext_or_auth_cookie_file_name();
+ retval = init_cookie_authentication(fname, EXT_OR_PORT_AUTH_COOKIE_HEADER,
+ EXT_OR_PORT_AUTH_COOKIE_HEADER_LEN,
+ &ext_or_auth_cookie,
+ &ext_or_auth_cookie_is_set);
+ tor_free(fname);
+ return retval;
+}
+
+/** Read data from <b>conn</b> and see if the client sent us the
+ * authentication type that she prefers to use in this session.
+ *
+ * Return -1 if we received corrupted data or if we don't support the
+ * authentication type. Return 0 if we need more data in
+ * <b>conn</b>. Return 1 if the authentication type negotiation was
+ * successful. */
+static int
+connection_ext_or_auth_neg_auth_type(connection_t *conn)
+{
+ char authtype[1] = {0};
+
+ if (connection_get_inbuf_len(conn) < 1)
+ return 0;
+
+ if (connection_fetch_from_buf(authtype, 1, conn) < 0)
+ return -1;
+
+ log_debug(LD_GENERAL, "Client wants us to use %d auth type", authtype[0]);
+ if (authtype[0] != EXT_OR_AUTHTYPE_SAFECOOKIE) {
+ /* '1' is the only auth type supported atm */
+ return -1;
+ }
+
+ conn->state = EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_NONCE;
+ return 1;
+}
+
+/** DOCDOC */
+STATIC int
+handle_client_auth_nonce(const char *client_nonce, size_t client_nonce_len,
+ char **client_hash_out,
+ char **reply_out, size_t *reply_len_out)
+{
+ char server_hash[EXT_OR_PORT_AUTH_HASH_LEN] = {0};
+ char server_nonce[EXT_OR_PORT_AUTH_NONCE_LEN] = {0};
+ char *reply;
+ size_t reply_len;
+
+ if (client_nonce_len != EXT_OR_PORT_AUTH_NONCE_LEN)
+ return -1;
+
+ /* Get our nonce */
+ if (crypto_rand(server_nonce, EXT_OR_PORT_AUTH_NONCE_LEN) < 0)
+ return -1;
+
+ { /* set up macs */
+ size_t hmac_s_msg_len = strlen(EXT_OR_PORT_AUTH_SERVER_TO_CLIENT_CONST) +
+ 2*EXT_OR_PORT_AUTH_NONCE_LEN;
+ size_t hmac_c_msg_len = strlen(EXT_OR_PORT_AUTH_CLIENT_TO_SERVER_CONST) +
+ 2*EXT_OR_PORT_AUTH_NONCE_LEN;
+
+ char *hmac_s_msg = tor_malloc_zero(hmac_s_msg_len);
+ char *hmac_c_msg = tor_malloc_zero(hmac_c_msg_len);
+ char *correct_client_hash = tor_malloc_zero(EXT_OR_PORT_AUTH_HASH_LEN);
+
+ memcpy(hmac_s_msg,
+ EXT_OR_PORT_AUTH_SERVER_TO_CLIENT_CONST,
+ strlen(EXT_OR_PORT_AUTH_SERVER_TO_CLIENT_CONST));
+ memcpy(hmac_s_msg + strlen(EXT_OR_PORT_AUTH_SERVER_TO_CLIENT_CONST),
+ client_nonce, EXT_OR_PORT_AUTH_NONCE_LEN);
+ memcpy(hmac_s_msg + strlen(EXT_OR_PORT_AUTH_SERVER_TO_CLIENT_CONST) +
+ EXT_OR_PORT_AUTH_NONCE_LEN,
+ server_nonce, EXT_OR_PORT_AUTH_NONCE_LEN);
+
+ memcpy(hmac_c_msg,
+ EXT_OR_PORT_AUTH_CLIENT_TO_SERVER_CONST,
+ strlen(EXT_OR_PORT_AUTH_CLIENT_TO_SERVER_CONST));
+ memcpy(hmac_c_msg + strlen(EXT_OR_PORT_AUTH_CLIENT_TO_SERVER_CONST),
+ client_nonce, EXT_OR_PORT_AUTH_NONCE_LEN);
+ memcpy(hmac_c_msg + strlen(EXT_OR_PORT_AUTH_CLIENT_TO_SERVER_CONST) +
+ EXT_OR_PORT_AUTH_NONCE_LEN,
+ server_nonce, EXT_OR_PORT_AUTH_NONCE_LEN);
+
+ crypto_hmac_sha256(server_hash,
+ (char*)ext_or_auth_cookie,
+ EXT_OR_PORT_AUTH_COOKIE_LEN,
+ hmac_s_msg,
+ hmac_s_msg_len);
+
+ crypto_hmac_sha256(correct_client_hash,
+ (char*)ext_or_auth_cookie,
+ EXT_OR_PORT_AUTH_COOKIE_LEN,
+ hmac_c_msg,
+ hmac_c_msg_len);
+
+ /* Store the client hash we generated. We will need to compare it
+ with the hash sent by the client. */
+ *client_hash_out = correct_client_hash;
+
+ memwipe(hmac_s_msg, 0, hmac_s_msg_len);
+ memwipe(hmac_c_msg, 0, hmac_c_msg_len);
+
+ tor_free(hmac_s_msg);
+ tor_free(hmac_c_msg);
+ }
+
+ { /* debug logging */ /* XXX disable this codepath if not logging on debug?*/
+ char server_hash_encoded[(2*EXT_OR_PORT_AUTH_HASH_LEN) + 1];
+ char server_nonce_encoded[(2*EXT_OR_PORT_AUTH_NONCE_LEN) + 1];
+ char client_nonce_encoded[(2*EXT_OR_PORT_AUTH_NONCE_LEN) + 1];
+
+ base16_encode(server_hash_encoded, sizeof(server_hash_encoded),
+ server_hash, sizeof(server_hash));
+ base16_encode(server_nonce_encoded, sizeof(server_nonce_encoded),
+ server_nonce, sizeof(server_nonce));
+ base16_encode(client_nonce_encoded, sizeof(client_nonce_encoded),
+ client_nonce, sizeof(client_nonce));
+
+ log_debug(LD_GENERAL,
+ "server_hash: '%s'\nserver_nonce: '%s'\nclient_nonce: '%s'",
+ server_hash_encoded, server_nonce_encoded, client_nonce_encoded);
+
+ memwipe(server_hash_encoded, 0, sizeof(server_hash_encoded));
+ memwipe(server_nonce_encoded, 0, sizeof(server_nonce_encoded));
+ memwipe(client_nonce_encoded, 0, sizeof(client_nonce_encoded));
+ }
+
+ { /* write reply: (server_hash, server_nonce) */
+
+ reply_len = EXT_OR_PORT_AUTH_COOKIE_LEN+EXT_OR_PORT_AUTH_NONCE_LEN;
+ reply = tor_malloc_zero(reply_len);
+ memcpy(reply, server_hash, EXT_OR_PORT_AUTH_HASH_LEN);
+ memcpy(reply + EXT_OR_PORT_AUTH_HASH_LEN, server_nonce,
+ EXT_OR_PORT_AUTH_NONCE_LEN);
+ }
+
+ *reply_out = reply;
+ *reply_len_out = reply_len;
+
+ return 0;
+}
+
+/** Read the client's nonce out of <b>conn</b>, setup the safe-cookie
+ * crypto, and then send our own hash and nonce to the client
+ *
+ * Return -1 if there was an error; return 0 if we need more data in
+ * <b>conn</b>, and return 1 if we successfully retrieved the
+ * client's nonce and sent our own. */
+static int
+connection_ext_or_auth_handle_client_nonce(connection_t *conn)
+{
+ char client_nonce[EXT_OR_PORT_AUTH_NONCE_LEN];
+ char *reply=NULL;
+ size_t reply_len=0;
+
+ if (!ext_or_auth_cookie_is_set) { /* this should not happen */
+ log_warn(LD_BUG, "Extended ORPort authentication cookie was not set. "
+ "That's weird since we should have done that on startup. "
+ "This might be a Tor bug, please file a bug report. ");
+ return -1;
+ }
+
+ if (connection_get_inbuf_len(conn) < EXT_OR_PORT_AUTH_NONCE_LEN)
+ return 0;
+
+ if (connection_fetch_from_buf(client_nonce,
+ EXT_OR_PORT_AUTH_NONCE_LEN, conn) < 0)
+ return -1;
+
+ /* We extract the ClientNonce from the received data, and use it to
+ calculate ServerHash and ServerNonce according to proposal 217.
+
+ We also calculate our own ClientHash value and save it in the
+ connection state. We validate it later against the ClientHash
+ sent by the client. */
+ if (handle_client_auth_nonce(client_nonce, sizeof(client_nonce),
+ &TO_OR_CONN(conn)->ext_or_auth_correct_client_hash,
+ &reply, &reply_len) < 0)
+ return -1;
+
+ connection_write_to_buf(reply, reply_len, conn);
+
+ memwipe(reply, 0, reply_len);
+ tor_free(reply);
+
+ log_debug(LD_GENERAL, "Got client nonce, and sent our own nonce and hash.");
+
+ conn->state = EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH;
+ return 1;
+}
+
+#define connection_ext_or_auth_send_result_success(c) \
+ connection_ext_or_auth_send_result(c, 1)
+#define connection_ext_or_auth_send_result_fail(c) \
+ connection_ext_or_auth_send_result(c, 0)
+
+/** Send authentication results to <b>conn</b>. Successful results if
+ * <b>success</b> is set; failure results otherwise. */
+static void
+connection_ext_or_auth_send_result(connection_t *conn, int success)
+{
+ if (success)
+ connection_write_to_buf("\x01", 1, conn);
+ else
+ connection_write_to_buf("\x00", 1, conn);
+}
+
+/** Receive the client's hash from <b>conn</b>, validate that it's
+ * correct, and then send the authentication results to the client.
+ *
+ * Return -1 if there was an error during validation; return 0 if we
+ * need more data in <b>conn</b>, and return 1 if we successfully
+ * validated the client's hash and sent a happy authentication
+ * result. */
+static int
+connection_ext_or_auth_handle_client_hash(connection_t *conn)
+{
+ char provided_client_hash[EXT_OR_PORT_AUTH_HASH_LEN] = {0};
+
+ if (connection_get_inbuf_len(conn) < EXT_OR_PORT_AUTH_HASH_LEN)
+ return 0;
+
+ if (connection_fetch_from_buf(provided_client_hash,
+ EXT_OR_PORT_AUTH_HASH_LEN, conn) < 0)
+ return -1;
+
+ if (tor_memneq(TO_OR_CONN(conn)->ext_or_auth_correct_client_hash,
+ provided_client_hash, EXT_OR_PORT_AUTH_HASH_LEN)) {
+ log_warn(LD_GENERAL, "Incorrect client hash. Authentication failed.");
+ connection_ext_or_auth_send_result_fail(conn);
+ return -1;
+ }
+
+ log_debug(LD_GENERAL, "Got client's hash and it was legit.");
+
+ /* send positive auth result */
+ connection_ext_or_auth_send_result_success(conn);
+ conn->state = EXT_OR_CONN_STATE_OPEN;
+ return 1;
+}
+
+/** Handle data from <b>or_conn</b> received on Extended ORPort.
+ * Return -1 on error. 0 on unsufficient data. 1 on correct. */
+static int
+connection_ext_or_auth_process_inbuf(or_connection_t *or_conn)
+{
+ connection_t *conn = TO_CONN(or_conn);
+
+ /* State transitions of the Extended ORPort authentication protocol:
+
+ EXT_OR_CONN_STATE_AUTH_WAIT_AUTH_TYPE (start state) ->
+ EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_NONCE ->
+ EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH ->
+ EXT_OR_CONN_STATE_OPEN
+
+ During EXT_OR_CONN_STATE_OPEN, data is handled by
+ connection_ext_or_process_inbuf().
+ */
+
+ switch (conn->state) { /* Functionify */
+ case EXT_OR_CONN_STATE_AUTH_WAIT_AUTH_TYPE:
+ return connection_ext_or_auth_neg_auth_type(conn);
+
+ case EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_NONCE:
+ return connection_ext_or_auth_handle_client_nonce(conn);
+
+ case EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH:
+ return connection_ext_or_auth_handle_client_hash(conn);
+
+ default:
+ log_warn(LD_BUG, "Encountered unexpected connection state %d while trying "
+ "to process Extended ORPort authentication data.", conn->state);
+ return -1;
+ }
+}
+
+/** Extended ORPort commands (Transport-to-Bridge) */
+#define EXT_OR_CMD_TB_DONE 0x0000
+#define EXT_OR_CMD_TB_USERADDR 0x0001
+#define EXT_OR_CMD_TB_TRANSPORT 0x0002
+
+/** Extended ORPort commands (Bridge-to-Transport) */
+#define EXT_OR_CMD_BT_OKAY 0x1000
+#define EXT_OR_CMD_BT_DENY 0x1001
+#define EXT_OR_CMD_BT_CONTROL 0x1002
+
+/** Process a USERADDR command from the Extended
+ * ORPort. <b>payload</b> is a payload of size <b>len</b>.
+ *
+ * If the USERADDR command was well formed, change the address of
+ * <b>conn</b> to the address on the USERADDR command.
+ *
+ * Return 0 on success and -1 on error. */
+static int
+connection_ext_or_handle_cmd_useraddr(connection_t *conn,
+ const char *payload, uint16_t len)
+{
+ /* Copy address string. */
+ tor_addr_t addr;
+ uint16_t port;
+ char *addr_str;
+ char *address_part=NULL;
+ int res;
+ if (memchr(payload, '\0', len)) {
+ log_fn(LOG_PROTOCOL_WARN, LD_NET, "Unexpected NUL in ExtORPort UserAddr");
+ return -1;
+ }
+
+ addr_str = tor_memdup_nulterm(payload, len);
+
+ res = tor_addr_port_split(LOG_INFO, addr_str, &address_part, &port);
+ tor_free(addr_str);
+ if (res<0)
+ return -1;
+
+ res = tor_addr_parse(&addr, address_part);
+ tor_free(address_part);
+ if (res<0)
+ return -1;
+
+ { /* do some logging */
+ char *old_address = tor_dup_addr(&conn->addr);
+ char *new_address = tor_dup_addr(&addr);
+
+ log_debug(LD_NET, "Received USERADDR."
+ "We rewrite our address from '%s:%u' to '%s:%u'.",
+ safe_str(old_address), conn->port, safe_str(new_address), port);
+
+ tor_free(old_address);
+ tor_free(new_address);
+ }
+
+ /* record the address */
+ tor_addr_copy(&conn->addr, &addr);
+ conn->port = port;
+ if (conn->address) {
+ tor_free(conn->address);
+ }
+ conn->address = tor_dup_addr(&addr);
+
+ return 0;
+}
+
+/** Process a TRANSPORT command from the Extended
+ * ORPort. <b>payload</b> is a payload of size <b>len</b>.
+ *
+ * If the TRANSPORT command was well formed, register the name of the
+ * transport on <b>conn</b>.
+ *
+ * Return 0 on success and -1 on error. */
+static int
+connection_ext_or_handle_cmd_transport(or_connection_t *conn,
+ const char *payload, uint16_t len)
+{
+ char *transport_str;
+ if (memchr(payload, '\0', len)) {
+ log_fn(LOG_PROTOCOL_WARN, LD_NET, "Unexpected NUL in ExtORPort Transport");
+ return -1;
+ }
+
+ transport_str = tor_memdup_nulterm(payload, len);
+
+ /* Transport names MUST be C-identifiers. */
+ if (!string_is_C_identifier(transport_str)) {
+ tor_free(transport_str);
+ return -1;
+ }
+
+ /* If ext_or_transport is already occupied (because the PT sent two
+ * TRANSPORT commands), deallocate the old name and keep the new
+ * one */
+ if (conn->ext_or_transport)
+ tor_free(conn->ext_or_transport);
+
+ conn->ext_or_transport = transport_str;
+ return 0;
+}
+
+#define EXT_OR_CONN_STATE_IS_AUTHENTICATING(st) \
+ ((st) <= EXT_OR_CONN_STATE_AUTH_MAX)
+
+/** Process Extended ORPort messages from <b>or_conn</b>. */
+int
+connection_ext_or_process_inbuf(or_connection_t *or_conn)
+{
+ connection_t *conn = TO_CONN(or_conn);
+ ext_or_cmd_t *command;
+ int r;
+
+ /* DOCDOC Document the state machine and transitions in this function */
+
+ /* If we are still in the authentication stage, process traffic as
+ authentication data: */
+ while (EXT_OR_CONN_STATE_IS_AUTHENTICATING(conn->state)) {
+ log_debug(LD_GENERAL, "Got Extended ORPort authentication data (%u).",
+ (unsigned int) connection_get_inbuf_len(conn));
+ r = connection_ext_or_auth_process_inbuf(or_conn);
+ if (r < 0) {
+ connection_mark_for_close(conn);
+ return -1;
+ } else if (r == 0) {
+ return 0;
+ }
+ /* if r > 0, loop and process more data (if any). */
+ }
+
+ while (1) {
+ log_debug(LD_GENERAL, "Got Extended ORPort data.");
+ command = NULL;
+ r = connection_fetch_ext_or_cmd_from_buf(conn, &command);
+ if (r < 0)
+ goto err;
+ else if (r == 0)
+ return 0; /* need to wait for more data */
+
+ /* Got a command! */
+ tor_assert(command);
+
+ if (command->cmd == EXT_OR_CMD_TB_DONE) {
+ if (connection_get_inbuf_len(conn)) {
+ /* The inbuf isn't empty; the client is misbehaving. */
+ goto err;
+ }
+
+ log_debug(LD_NET, "Received DONE.");
+
+ /* If the transport proxy did not use the TRANSPORT command to
+ * specify the transport name, mark this as unknown transport. */
+ if (!or_conn->ext_or_transport) {
+ /* We write this string this way to avoid ??>, which is a C
+ * trigraph. */
+ or_conn->ext_or_transport = tor_strdup("<?" "?>");
+ }
+
+ connection_write_ext_or_command(conn, EXT_OR_CMD_BT_OKAY, NULL, 0);
+
+ /* can't transition immediately; need to flush first. */
+ conn->state = EXT_OR_CONN_STATE_FLUSHING;
+ connection_stop_reading(conn);
+ } else if (command->cmd == EXT_OR_CMD_TB_USERADDR) {
+ if (connection_ext_or_handle_cmd_useraddr(conn,
+ command->body, command->len) < 0)
+ goto err;
+ } else if (command->cmd == EXT_OR_CMD_TB_TRANSPORT) {
+ if (connection_ext_or_handle_cmd_transport(or_conn,
+ command->body, command->len) < 0)
+ goto err;
+ } else {
+ log_notice(LD_NET,"Got Extended ORPort command we don't regognize (%u).",
+ command->cmd);
+ }
+
+ ext_or_cmd_free(command);
+ }
+
+ return 0;
+
+ err:
+ ext_or_cmd_free(command);
+ connection_mark_for_close(conn);
+ return -1;
+}
+
+/** <b>conn</b> finished flushing Extended ORPort messages to the
+ * network, and is now ready to accept OR traffic. This function
+ * does the transition. */
+int
+connection_ext_or_finished_flushing(or_connection_t *conn)
+{
+ if (conn->base_.state == EXT_OR_CONN_STATE_FLUSHING) {
+ connection_start_reading(TO_CONN(conn));
+ connection_ext_or_transition(conn);
+ }
+ return 0;
+}
+
+/** Initiate Extended ORPort authentication, by sending the list of
+ * supported authentication types to the client. */
+int
+connection_ext_or_start_auth(or_connection_t *or_conn)
+{
+ connection_t *conn = TO_CONN(or_conn);
+ const uint8_t authtypes[] = {
+ /* We only support authtype '1' for now. */
+ EXT_OR_AUTHTYPE_SAFECOOKIE,
+ /* Marks the end of the list. */
+ 0
+ };
+
+ log_debug(LD_GENERAL,
+ "ExtORPort authentication: Sending supported authentication types");
+
+ connection_write_to_buf((const char *)authtypes, sizeof(authtypes), conn);
+ conn->state = EXT_OR_CONN_STATE_AUTH_WAIT_AUTH_TYPE;
+
+ return 0;
+}
+
+/** Free any leftover allocated memory of the ext_orport.c subsystem. */
+void
+ext_orport_free_all(void)
+{
+ if (ext_or_auth_cookie) /* Free the auth cookie */
+ tor_free(ext_or_auth_cookie);
+}
+
diff --git a/src/or/ext_orport.h b/src/or/ext_orport.h
new file mode 100644
index 000000000..ce45e5f41
--- /dev/null
+++ b/src/or/ext_orport.h
@@ -0,0 +1,42 @@
+/* Copyright (c) 2001 Matej Pfajfar.
+ * Copyright (c) 2001-2004, Roger Dingledine.
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
+ * Copyright (c) 2007-2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#ifndef EXT_ORPORT_H
+#define EXT_ORPORT_H
+
+int connection_ext_or_start_auth(or_connection_t *or_conn);
+
+ext_or_cmd_t *ext_or_cmd_new(uint16_t len);
+void ext_or_cmd_free(ext_or_cmd_t *cmd);
+void connection_or_set_ext_or_identifier(or_connection_t *conn);
+void connection_or_remove_from_ext_or_id_map(or_connection_t *conn);
+void connection_or_clear_ext_or_id_map(void);
+or_connection_t *connection_or_get_by_ext_or_id(const char *id);
+
+int connection_ext_or_finished_flushing(or_connection_t *conn);
+int connection_ext_or_process_inbuf(or_connection_t *or_conn);
+
+int init_ext_or_cookie_authentication(int is_enabled);
+char *get_ext_or_auth_cookie_file_name(void);
+void ext_orport_free_all(void);
+
+#ifdef EXT_ORPORT_PRIVATE
+STATIC int connection_write_ext_or_command(connection_t *conn,
+ uint16_t command,
+ const char *body,
+ size_t bodylen);
+STATIC int handle_client_auth_nonce(const char *client_nonce,
+ size_t client_nonce_len,
+ char **client_hash_out,
+ char **reply_out, size_t *reply_len_out);
+#ifdef TOR_UNIT_TESTS
+extern uint8_t *ext_or_auth_cookie;
+extern int ext_or_auth_cookie_is_set;
+#endif
+#endif
+
+#endif
+
diff --git a/src/or/geoip.c b/src/or/geoip.c
index d6e8ee0d0..dc4730c81 100644
--- a/src/or/geoip.c
+++ b/src/or/geoip.c
@@ -120,7 +120,7 @@ geoip_add_entry(const tor_addr_t *low, const tor_addr_t *high,
/** Add an entry to the GeoIP table indicated by <b>family</b>,
* parsing it from <b>line</b>. The format is as for geoip_load_file(). */
-/*private*/ int
+STATIC int
geoip_parse_entry(const char *line, sa_family_t family)
{
tor_addr_t low_addr, high_addr;
@@ -363,7 +363,7 @@ geoip_load_file(sa_family_t family, const char *filename)
* be less than geoip_get_n_countries(). To decode it, call
* geoip_get_country_name().
*/
-int
+STATIC int
geoip_get_country_by_ipv4(uint32_t ipaddr)
{
geoip_ipv4_entry_t *ent;
@@ -379,7 +379,7 @@ geoip_get_country_by_ipv4(uint32_t ipaddr)
* 0 for the 'unknown country'. The return value will always be less than
* geoip_get_n_countries(). To decode it, call geoip_get_country_name().
*/
-int
+STATIC int
geoip_get_country_by_ipv6(const struct in6_addr *addr)
{
geoip_ipv6_entry_t *ent;
@@ -461,6 +461,10 @@ geoip_db_digest(sa_family_t family)
typedef struct clientmap_entry_t {
HT_ENTRY(clientmap_entry_t) node;
tor_addr_t addr;
+ /* Name of pluggable transport used by this client. NULL if no
+ pluggable transport was used. */
+ char *transport_name;
+
/** Time when we last saw this IP address, in MINUTES since the epoch.
*
* (This will run out of space around 4011 CE. If Tor is still in use around
@@ -482,12 +486,18 @@ static HT_HEAD(clientmap, clientmap_entry_t) client_history =
static INLINE unsigned
clientmap_entry_hash(const clientmap_entry_t *a)
{
- return ht_improve_hash(tor_addr_hash(&a->addr));
+ unsigned h = tor_addr_hash(&a->addr);
+ if (a->transport_name)
+ h += ht_string_hash(a->transport_name);
+ return ht_improve_hash(h);
}
/** Hashtable helper: compare two clientmap_entry_t values for equality. */
static INLINE int
clientmap_entries_eq(const clientmap_entry_t *a, const clientmap_entry_t *b)
{
+ if (strcmp_opt(a->transport_name, b->transport_name))
+ return 0;
+
return !tor_addr_compare(&a->addr, &b->addr, CMP_EXACT) &&
a->action == b->action;
}
@@ -497,6 +507,17 @@ HT_PROTOTYPE(clientmap, clientmap_entry_t, node, clientmap_entry_hash,
HT_GENERATE(clientmap, clientmap_entry_t, node, clientmap_entry_hash,
clientmap_entries_eq, 0.6, malloc, realloc, free);
+/** Free all storage held by <b>ent</b>. */
+static void
+clientmap_entry_free(clientmap_entry_t *ent)
+{
+ if (!ent)
+ return;
+
+ tor_free(ent->transport_name);
+ tor_free(ent);
+}
+
/** Clear history of connecting clients used by entry and bridge stats. */
static void
client_history_clear(void)
@@ -507,7 +528,7 @@ client_history_clear(void)
if ((*ent)->action == GEOIP_CLIENT_CONNECT) {
this = *ent;
next = HT_NEXT_RMV(clientmap, &client_history, ent);
- tor_free(this);
+ clientmap_entry_free(this);
} else {
next = HT_NEXT(clientmap, &client_history, ent);
}
@@ -519,10 +540,14 @@ client_history_clear(void)
* configured accordingly. */
void
geoip_note_client_seen(geoip_client_action_t action,
- const tor_addr_t *addr, time_t now)
+ const tor_addr_t *addr,
+ const char *transport_name,
+ time_t now)
{
const or_options_t *options = get_options();
clientmap_entry_t lookup, *ent;
+ memset(&lookup, 0, sizeof(clientmap_entry_t));
+
if (action == GEOIP_CLIENT_CONNECT) {
/* Only remember statistics as entry guard or as bridge. */
if (!options->EntryStatistics &&
@@ -534,12 +559,20 @@ geoip_note_client_seen(geoip_client_action_t action,
return;
}
+ log_debug(LD_GENERAL, "Seen client from '%s' with transport '%s'.",
+ safe_str_client(fmt_addr((addr))),
+ transport_name ? transport_name : "<no transport>");
+
tor_addr_copy(&lookup.addr, addr);
lookup.action = (int)action;
+ lookup.transport_name = (char*) transport_name;
ent = HT_FIND(clientmap, &client_history, &lookup);
+
if (! ent) {
ent = tor_malloc_zero(sizeof(clientmap_entry_t));
tor_addr_copy(&ent->addr, addr);
+ if (transport_name)
+ ent->transport_name = tor_strdup(transport_name);
ent->action = (int)action;
HT_INSERT(clientmap, &client_history, ent);
}
@@ -566,7 +599,7 @@ remove_old_client_helper_(struct clientmap_entry_t *ent, void *_cutoff)
{
time_t cutoff = *(time_t*)_cutoff / 60;
if (ent->last_seen_in_minutes < cutoff) {
- tor_free(ent);
+ clientmap_entry_free(ent);
return 1;
} else {
return 0;
@@ -769,6 +802,106 @@ geoip_change_dirreq_state(uint64_t dirreq_id, dirreq_type_t type,
}
}
+/** Return the bridge-ip-transports string that should be inserted in
+ * our extra-info descriptor. Return NULL if the bridge-ip-transports
+ * line should be empty. */
+char *
+geoip_get_transport_history(void)
+{
+ unsigned granularity = IP_GRANULARITY;
+ /** String hash table <name of transport> -> <number of users>. */
+ strmap_t *transport_counts = strmap_new();
+
+ /** Smartlist that contains copies of the names of the transports
+ that have been used. */
+ smartlist_t *transports_used = smartlist_new();
+
+ /* Special string to signify that no transport was used for this
+ connection. Pluggable transport names can't have symbols in their
+ names, so this string will never collide with a real transport. */
+ static const char* no_transport_str = "<OR>";
+
+ clientmap_entry_t **ent;
+ const char *transport_name = NULL;
+ smartlist_t *string_chunks = smartlist_new();
+ char *the_string = NULL;
+
+ /* If we haven't seen any clients yet, return NULL. */
+ if (HT_EMPTY(&client_history))
+ goto done;
+
+ /** We do the following steps to form the transport history string:
+ * a) Foreach client that uses a pluggable transport, we increase the
+ * times that transport was used by one. If the client did not use
+ * a transport, we increase the number of times someone connected
+ * without obfuscation.
+ * b) Foreach transport we observed, we write its transport history
+ * string and push it to string_chunks. So, for example, if we've
+ * seen 665 obfs2 clients, we write "obfs2=665".
+ * c) We concatenate string_chunks to form the final string.
+ */
+
+ log_debug(LD_GENERAL,"Starting iteration for transport history. %d clients.",
+ HT_SIZE(&client_history));
+
+ /* Loop through all clients. */
+ HT_FOREACH(ent, clientmap, &client_history) {
+ uintptr_t val;
+ void *ptr;
+ transport_name = (*ent)->transport_name;
+ if (!transport_name)
+ transport_name = no_transport_str;
+
+ /* Increase the count for this transport name. */
+ ptr = strmap_get(transport_counts, transport_name);
+ val = (uintptr_t)ptr;
+ val++;
+ ptr = (void*)val;
+ strmap_set(transport_counts, transport_name, ptr);
+
+ /* If it's the first time we see this transport, note it. */
+ if (val == 1)
+ smartlist_add(transports_used, tor_strdup(transport_name));
+
+ log_debug(LD_GENERAL, "Client from '%s' with transport '%s'. "
+ "I've now seen %d clients.",
+ safe_str_client(fmt_addr(&(*ent)->addr)),
+ transport_name ? transport_name : "<no transport>",
+ (int)val);
+ }
+
+ /* Sort the transport names (helps with unit testing). */
+ smartlist_sort_strings(transports_used);
+
+ /* Loop through all seen transports. */
+ SMARTLIST_FOREACH_BEGIN(transports_used, const char *, transport_name) {
+ void *transport_count_ptr = strmap_get(transport_counts, transport_name);
+ uintptr_t transport_count = (uintptr_t) transport_count_ptr;
+
+ log_debug(LD_GENERAL, "We got "U64_FORMAT" clients with transport '%s'.",
+ U64_PRINTF_ARG((uint64_t)transport_count), transport_name);
+
+ smartlist_add_asprintf(string_chunks, "%s="U64_FORMAT,
+ transport_name,
+ U64_PRINTF_ARG(round_uint64_to_next_multiple_of(
+ (uint64_t)transport_count,
+ granularity)));
+ } SMARTLIST_FOREACH_END(transport_name);
+
+ the_string = smartlist_join_strings(string_chunks, ",", 0, NULL);
+
+ log_debug(LD_GENERAL, "Final bridge-ip-transports string: '%s'", the_string);
+
+ done:
+ strmap_free(transport_counts, NULL);
+ SMARTLIST_FOREACH(transports_used, char *, s, tor_free(s));
+ smartlist_free(transports_used);
+ SMARTLIST_FOREACH(string_chunks, char *, s, tor_free(s));
+ smartlist_free(string_chunks);
+
+ return the_string;
+}
+
/** Return a newly allocated comma-separated string containing statistics
* on network status downloads. The string contains the number of completed
* requests, timeouts, and still running requests as well as the download
@@ -1037,7 +1170,7 @@ geoip_reset_dirreq_stats(time_t now)
if ((*ent)->action == GEOIP_CLIENT_NETWORKSTATUS) {
this = *ent;
next = HT_NEXT_RMV(clientmap, &client_history, ent);
- tor_free(this);
+ clientmap_entry_free(this);
} else {
next = HT_NEXT(clientmap, &client_history, ent);
}
@@ -1189,6 +1322,8 @@ validate_bridge_stats(const char *stats_str, time_t now)
const char *BRIDGE_STATS_END = "bridge-stats-end ";
const char *BRIDGE_IPS = "bridge-ips ";
const char *BRIDGE_IPS_EMPTY_LINE = "bridge-ips\n";
+ const char *BRIDGE_TRANSPORTS = "bridge-ip-transports ";
+ const char *BRIDGE_TRANSPORTS_EMPTY_LINE = "bridge-ip-transports\n";
const char *tmp;
time_t stats_end_time;
int seconds;
@@ -1223,6 +1358,15 @@ validate_bridge_stats(const char *stats_str, time_t now)
return 0;
}
+ /* Parse: "bridge-ip-transports PT=N,PT=N,..." */
+ tmp = find_str_at_start_of_line(stats_str, BRIDGE_TRANSPORTS);
+ if (!tmp) {
+ /* Look if there is an empty "bridge-ip-transports" line */
+ tmp = find_str_at_start_of_line(stats_str, BRIDGE_TRANSPORTS_EMPTY_LINE);
+ if (!tmp)
+ return 0;
+ }
+
return 1;
}
@@ -1236,7 +1380,8 @@ static char *bridge_stats_extrainfo = NULL;
char *
geoip_format_bridge_stats(time_t now)
{
- char *out = NULL, *country_data = NULL, *ipver_data = NULL;
+ char *out = NULL;
+ char *country_data = NULL, *ipver_data = NULL, *transport_data = NULL;
long duration = now - start_of_bridge_stats_interval;
char written[ISO_TIME_LEN+1];
@@ -1247,16 +1392,20 @@ geoip_format_bridge_stats(time_t now)
format_iso_time(written, now);
geoip_get_client_history(GEOIP_CLIENT_CONNECT, &country_data, &ipver_data);
+ transport_data = geoip_get_transport_history();
tor_asprintf(&out,
"bridge-stats-end %s (%ld s)\n"
"bridge-ips %s\n"
- "bridge-ip-versions %s\n",
+ "bridge-ip-versions %s\n"
+ "bridge-ip-transports %s\n",
written, duration,
country_data ? country_data : "",
- ipver_data ? ipver_data : "");
+ ipver_data ? ipver_data : "",
+ transport_data ? transport_data : "");
tor_free(country_data);
tor_free(ipver_data);
+ tor_free(transport_data);
return out;
}
@@ -1515,7 +1664,7 @@ geoip_free_all(void)
for (ent = HT_START(clientmap, &client_history); ent != NULL; ent = next) {
this = *ent;
next = HT_NEXT_RMV(clientmap, &client_history, ent);
- tor_free(this);
+ clientmap_entry_free(this);
}
HT_CLEAR(clientmap, &client_history);
}
@@ -1530,5 +1679,6 @@ geoip_free_all(void)
}
clear_geoip_db();
+ tor_free(bridge_stats_extrainfo);
}
diff --git a/src/or/geoip.h b/src/or/geoip.h
index ebefee5f4..b9b53c300 100644
--- a/src/or/geoip.h
+++ b/src/or/geoip.h
@@ -12,10 +12,12 @@
#ifndef TOR_GEOIP_H
#define TOR_GEOIP_H
+#include "testsupport.h"
+
#ifdef GEOIP_PRIVATE
-int geoip_parse_entry(const char *line, sa_family_t family);
-int geoip_get_country_by_ipv4(uint32_t ipaddr);
-int geoip_get_country_by_ipv6(const struct in6_addr *addr);
+STATIC int geoip_parse_entry(const char *line, sa_family_t family);
+STATIC int geoip_get_country_by_ipv4(uint32_t ipaddr);
+STATIC int geoip_get_country_by_ipv6(const struct in6_addr *addr);
#endif
int should_record_bridge_info(const or_options_t *options);
int geoip_load_file(sa_family_t family, const char *filename);
@@ -27,10 +29,12 @@ const char *geoip_db_digest(sa_family_t family);
country_t geoip_get_country(const char *countrycode);
void geoip_note_client_seen(geoip_client_action_t action,
- const tor_addr_t *addr, time_t now);
+ const tor_addr_t *addr, const char *transport_name,
+ time_t now);
void geoip_remove_old_clients(time_t cutoff);
void geoip_note_ns_response(geoip_ns_response_t response);
+char *geoip_get_transport_history(void);
int geoip_get_client_history(geoip_client_action_t action,
char **country_str, char **ipver_str);
char *geoip_get_request_history(void);
diff --git a/src/or/hibernate.c b/src/or/hibernate.c
index a41257133..22c0f253d 100644
--- a/src/or/hibernate.c
+++ b/src/or/hibernate.c
@@ -1010,6 +1010,7 @@ getinfo_helper_accounting(control_connection_t *conn,
return 0;
}
+#ifdef TOR_UNIT_TESTS
/**
* Manually change the hibernation state. Private; used only by the unit
* tests.
@@ -1019,4 +1020,5 @@ hibernate_set_state_for_testing_(hibernate_state_t newstate)
{
hibernate_state = newstate;
}
+#endif
diff --git a/src/or/hibernate.h b/src/or/hibernate.h
index d2d6989e1..18832fbc6 100644
--- a/src/or/hibernate.h
+++ b/src/or/hibernate.h
@@ -45,8 +45,10 @@ typedef enum {
HIBERNATE_STATE_INITIAL=5
} hibernate_state_t;
+#ifdef TOR_UNIT_TESTS
void hibernate_set_state_for_testing_(hibernate_state_t newstate);
#endif
+#endif
#endif
diff --git a/src/or/include.am b/src/or/include.am
index 65dbeff53..8922e0397 100644
--- a/src/or/include.am
+++ b/src/or/include.am
@@ -1,5 +1,13 @@
bin_PROGRAMS+= src/or/tor
-noinst_LIBRARIES+= src/or/libtor.a
+noinst_LIBRARIES += \
+ src/or/libtor.a
+if UNITTESTS_ENABLED
+noinst_LIBRARIES += \
+ src/or/libtor-testing.a
+endif
+if COVERAGE_ENABLED
+noinst_PROGRAMS+= src/or/tor-cov
+endif
if BUILD_NT_SERVICES
tor_platform_source=src/or/ntmain.c
@@ -21,7 +29,7 @@ else
onion_ntor_source=
endif
-src_or_libtor_a_SOURCES = \
+LIBTOR_A_SOURCES = \
src/or/addressmap.c \
src/or/buffers.c \
src/or/channel.c \
@@ -48,6 +56,7 @@ src_or_libtor_a_SOURCES = \
src/or/fp_pair.c \
src/or/geoip.c \
src/or/entrynodes.c \
+ src/or/ext_orport.c \
src/or/hibernate.c \
src/or/main.c \
src/or/microdesc.c \
@@ -77,6 +86,9 @@ src_or_libtor_a_SOURCES = \
$(onion_ntor_source) \
src/or/config_codedigest.c
+src_or_libtor_a_SOURCES = $(LIBTOR_A_SOURCES)
+src_or_libtor_testing_a_SOURCES = $(LIBTOR_A_SOURCES)
+
#libtor_a_LIBADD = ../common/libor.a ../common/libor-crypto.a \
# ../common/libor-event.a
@@ -90,6 +102,9 @@ AM_CPPFLAGS += -DSHARE_DATADIR="\"$(datadir)\"" \
-DLOCALSTATEDIR="\"$(localstatedir)\"" \
-DBINDIR="\"$(bindir)\""
+src_or_libtor_testing_a_CPPFLAGS = -DTOR_UNIT_TESTS $(AM_CPPFLAGS)
+src_or_libtor_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+
# -L flags need to go in LDFLAGS. -l flags need to go in LDADD.
# This seems to matter nowhere but on windows, but I assure you that it
# matters a lot there, and is quite hard to debug if you forget to do it.
@@ -102,6 +117,18 @@ src_or_tor_LDADD = src/or/libtor.a src/common/libor.a \
@TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
@TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+if COVERAGE_ENABLED
+src_or_tor_cov_SOURCES = src/or/tor_main.c
+src_or_tor_cov_CPPFLAGS = -DTOR_UNIT_TESTS $(AM_CPPFLAGS)
+src_or_tor_cov_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
+src_or_tor_cov_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@
+src_or_tor_cov_LDADD = src/or/libtor-testing.a src/common/libor-testing.a \
+ src/common/libor-crypto-testing.a $(LIBDONNA) \
+ src/common/libor-event-testing.a \
+ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \
+ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@
+endif
+
ORHEADERS = \
src/or/addressmap.h \
src/or/buffers.h \
@@ -127,6 +154,7 @@ ORHEADERS = \
src/or/dns.h \
src/or/dnsserv.h \
src/or/eventdns_tor.h \
+ src/or/ext_orport.h \
src/or/fp_pair.h \
src/or/geoip.h \
src/or/entrynodes.h \
diff --git a/src/or/main.c b/src/or/main.c
index 8e2845f47..33e1c6437 100644
--- a/src/or/main.c
+++ b/src/or/main.c
@@ -52,11 +52,13 @@
#include "routerparse.h"
#include "statefile.h"
#include "status.h"
+#include "ext_orport.h"
#ifdef USE_DMALLOC
#include <dmalloc.h>
#include <openssl/crypto.h>
#endif
#include "memarea.h"
+#include "../common/sandbox.h"
#ifdef HAVE_EVENT2_EVENT_H
#include <event2/event.h>
@@ -412,6 +414,19 @@ connection_unlink(connection_t *conn)
connection_free(conn);
}
+/** Initialize the global connection list, closeable connection list,
+ * and active connection list. */
+STATIC void
+init_connection_lists(void)
+{
+ if (!connection_array)
+ connection_array = smartlist_new();
+ if (!closeable_connection_lst)
+ closeable_connection_lst = smartlist_new();
+ if (!active_linked_connection_lst)
+ active_linked_connection_lst = smartlist_new();
+}
+
/** Schedule <b>conn</b> to be closed. **/
void
add_connection_to_closeable_list(connection_t *conn)
@@ -505,8 +520,8 @@ connection_is_reading(connection_t *conn)
}
/** Tell the main loop to stop notifying <b>conn</b> of any read events. */
-void
-connection_stop_reading(connection_t *conn)
+MOCK_IMPL(void,
+connection_stop_reading,(connection_t *conn))
{
tor_assert(conn);
@@ -530,8 +545,8 @@ connection_stop_reading(connection_t *conn)
}
/** Tell the main loop to start notifying <b>conn</b> of any read events. */
-void
-connection_start_reading(connection_t *conn)
+MOCK_IMPL(void,
+connection_start_reading,(connection_t *conn))
{
tor_assert(conn);
@@ -570,8 +585,8 @@ connection_is_writing(connection_t *conn)
}
/** Tell the main loop to stop notifying <b>conn</b> of any write events. */
-void
-connection_stop_writing(connection_t *conn)
+MOCK_IMPL(void,
+connection_stop_writing,(connection_t *conn))
{
tor_assert(conn);
@@ -596,8 +611,8 @@ connection_stop_writing(connection_t *conn)
}
/** Tell the main loop to start notifying <b>conn</b> of any write events. */
-void
-connection_start_writing(connection_t *conn)
+MOCK_IMPL(void,
+connection_start_writing,(connection_t *conn))
{
tor_assert(conn);
@@ -685,7 +700,7 @@ connection_stop_reading_from_linked_conn(connection_t *conn)
}
/** Close all connections that have been scheduled to get closed. */
-static void
+STATIC void
close_closeable_connections(void)
{
int i;
@@ -1874,7 +1889,7 @@ do_hup(void)
}
/** Tor main loop. */
-/* static */ int
+int
do_main_loop(void)
{
int loop_result;
@@ -1891,6 +1906,13 @@ do_main_loop(void)
}
}
+#ifdef USE_BUFFEREVENTS
+ log_warn(LD_GENERAL, "Tor was compiled with the --enable-bufferevents "
+ "option. This is still experimental, and might cause strange "
+ "bugs. If you want a more stable Tor, be sure to build without "
+ "--enable-bufferevents.");
+#endif
+
handle_signals(1);
/* load the private keys, if we're supposed to have them, and set up the
@@ -2294,18 +2316,13 @@ handle_signals(int is_parent)
/** Main entry point for the Tor command-line client.
*/
-/* static */ int
+int
tor_init(int argc, char *argv[])
{
char buf[256];
int i, quiet = 0;
time_of_process_start = time(NULL);
- if (!connection_array)
- connection_array = smartlist_new();
- if (!closeable_connection_lst)
- closeable_connection_lst = smartlist_new();
- if (!active_linked_connection_lst)
- active_linked_connection_lst = smartlist_new();
+ init_connection_lists();
/* Have the log set up with our application name. */
tor_snprintf(buf, sizeof(buf), "Tor %s", get_version());
log_set_application_name(buf);
@@ -2494,6 +2511,8 @@ tor_free_all(int postfork)
memarea_clear_freelist();
nodelist_free_all();
microdesc_free_all();
+ ext_orport_free_all();
+ control_free_all();
if (!postfork) {
config_free_all();
or_state_free_all();
@@ -2560,7 +2579,7 @@ tor_cleanup(void)
}
/** Read/create keys as needed, and echo our fingerprint to stdout. */
-/* static */ int
+static int
do_list_fingerprint(void)
{
char buf[FINGERPRINT_LEN+1];
@@ -2590,7 +2609,7 @@ do_list_fingerprint(void)
/** Entry point for password hashing: take the desired password from
* the command line, and print its salted hash to stdout. **/
-/* static */ void
+static void
do_hash_password(void)
{
@@ -2697,6 +2716,14 @@ tor_main(int argc, char *argv[])
#endif
if (tor_init(argc, argv)<0)
return -1;
+
+ if (get_options()->Sandbox) {
+ if (tor_global_sandbox()) {
+ log_err(LD_BUG,"Failed to create syscall sandbox filter");
+ return -1;
+ }
+ }
+
switch (get_options()->command) {
case CMD_RUN_TOR:
#ifdef NT_SERVICE
diff --git a/src/or/main.h b/src/or/main.h
index 338449b6a..df302ffa7 100644
--- a/src/or/main.h
+++ b/src/or/main.h
@@ -36,12 +36,12 @@ typedef enum watchable_events {
} watchable_events_t;
void connection_watch_events(connection_t *conn, watchable_events_t events);
int connection_is_reading(connection_t *conn);
-void connection_stop_reading(connection_t *conn);
-void connection_start_reading(connection_t *conn);
+MOCK_DECL(void,connection_stop_reading,(connection_t *conn));
+MOCK_DECL(void,connection_start_reading,(connection_t *conn));
int connection_is_writing(connection_t *conn);
-void connection_stop_writing(connection_t *conn);
-void connection_start_writing(connection_t *conn);
+MOCK_DECL(void,connection_stop_writing,(connection_t *conn));
+MOCK_DECL(void,connection_start_writing,(connection_t *conn));
void connection_stop_reading_from_linked_conn(connection_t *conn);
@@ -66,11 +66,12 @@ void tor_free_all(int postfork);
int tor_main(int argc, char *argv[]);
-#ifdef MAIN_PRIVATE
int do_main_loop(void);
-int do_list_fingerprint(void);
-void do_hash_password(void);
int tor_init(int argc, char **argv);
+
+#ifdef MAIN_PRIVATE
+STATIC void init_connection_lists(void);
+STATIC void close_closeable_connections(void);
#endif
#endif
diff --git a/src/or/ntmain.c b/src/or/ntmain.c
index 8b67b8682..2fa074d0b 100644
--- a/src/or/ntmain.c
+++ b/src/or/ntmain.c
@@ -3,7 +3,6 @@
* Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
-#define MAIN_PRIVATE
#include "or.h"
#include "config.h"
#include "main.h"
diff --git a/src/or/or.h b/src/or/or.h
index 94fbe43f6..2daf12b82 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -228,8 +228,14 @@ typedef enum {
#define CONN_TYPE_AP_NATD_LISTENER 14
/** Type for sockets listening for DNS requests. */
#define CONN_TYPE_AP_DNS_LISTENER 15
-#define CONN_TYPE_MAX_ 15
-/* !!!! If CONN_TYPE_MAX_ is ever over 15, we must grow the type field in
+
+/** Type for connections from the Extended ORPort. */
+#define CONN_TYPE_EXT_OR 16
+/** Type for sockets listening for Extended ORPort connections. */
+#define CONN_TYPE_EXT_OR_LISTENER 17
+
+#define CONN_TYPE_MAX_ 17
+/* !!!! If _CONN_TYPE_MAX is ever over 31, we must grow the type field in
* connection_t. */
/* Proxy client types */
@@ -309,6 +315,25 @@ typedef enum {
#define OR_CONN_STATE_OPEN 8
#define OR_CONN_STATE_MAX_ 8
+/** States of the Extended ORPort protocol. Be careful before changing
+ * the numbers: they matter. */
+#define EXT_OR_CONN_STATE_MIN_ 1
+/** Extended ORPort authentication is waiting for the authentication
+ * type selected by the client. */
+#define EXT_OR_CONN_STATE_AUTH_WAIT_AUTH_TYPE 1
+/** Extended ORPort authentication is waiting for the client nonce. */
+#define EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_NONCE 2
+/** Extended ORPort authentication is waiting for the client hash. */
+#define EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH 3
+#define EXT_OR_CONN_STATE_AUTH_MAX 3
+/** Authentication finished and the Extended ORPort is now accepting
+ * traffic. */
+#define EXT_OR_CONN_STATE_OPEN 4
+/** Extended ORPort is flushing its last messages and preparing to
+ * start accepting OR connections. */
+#define EXT_OR_CONN_STATE_FLUSHING 5
+#define EXT_OR_CONN_STATE_MAX_ 5
+
#define EXIT_CONN_STATE_MIN_ 1
/** State for an exit connection: waiting for response from DNS farm. */
#define EXIT_CONN_STATE_RESOLVING 1
@@ -1082,9 +1107,17 @@ typedef struct var_cell_t {
uint8_t payload[FLEXIBLE_ARRAY_MEMBER];
} var_cell_t;
+/** A parsed Extended ORPort message. */
+typedef struct ext_or_cmd_t {
+ uint16_t cmd; /** Command type */
+ uint16_t len; /** Body length */
+ char body[FLEXIBLE_ARRAY_MEMBER]; /** Message body */
+} ext_or_cmd_t;
+
/** A cell as packed for writing to the network. */
typedef struct packed_cell_t {
- struct packed_cell_t *next; /**< Next cell queued on this circuit. */
+ /** Next cell queued on this circuit. */
+ TOR_SIMPLEQ_ENTRY(packed_cell_t) next;
char body[CELL_MAX_NETWORK_SIZE]; /**< Cell as packed for network. */
} packed_cell_t;
@@ -1106,8 +1139,8 @@ typedef struct insertion_time_queue_t {
/** A queue of cells on a circuit, waiting to be added to the
* or_connection_t's outbuf. */
typedef struct cell_queue_t {
- packed_cell_t *head; /**< The first cell, or NULL if the queue is empty. */
- packed_cell_t *tail; /**< The last cell, or NULL if the queue is empty. */
+ /** Linked list of packed_cell_t*/
+ TOR_SIMPLEQ_HEAD(cell_simpleq, packed_cell_t) head;
int n; /**< The number of cells in the queue. */
insertion_time_queue_t *insertion_times; /**< Insertion times of cells. */
} cell_queue_t;
@@ -1162,7 +1195,7 @@ typedef struct connection_t {
* *_CONNECTION_MAGIC. */
uint8_t state; /**< Current state of this connection. */
- unsigned int type:4; /**< What kind of connection is this? */
+ unsigned int type:5; /**< What kind of connection is this? */
unsigned int purpose:5; /**< Only used for DIR and EXIT types currently. */
/* The next fields are all one-bit booleans. Some are only applicable to
@@ -1404,6 +1437,9 @@ typedef struct or_handshake_state_t {
/**@}*/
} or_handshake_state_t;
+/** Length of Extended ORPort connection identifier. */
+#define EXT_OR_CONN_ID_LEN DIGEST_LEN /* 20 */
+
/** Subtype of connection_t for an "OR connection" -- that is, one that speaks
* cells over TLS. */
typedef struct or_connection_t {
@@ -1412,6 +1448,20 @@ typedef struct or_connection_t {
/** Hash of the public RSA key for the other side's identity key, or zeroes
* if the other side hasn't shown us a valid identity key. */
char identity_digest[DIGEST_LEN];
+
+ /** Extended ORPort connection identifier. */
+ char *ext_or_conn_id;
+ /** This is the ClientHash value we expect to receive from the
+ * client during the Extended ORPort authentication protocol. We
+ * compute it upon receiving the ClientNoce from the client, and we
+ * compare it with the acual ClientHash value sent by the
+ * client. */
+ char *ext_or_auth_correct_client_hash;
+ /** String carrying the name of the pluggable transport
+ * (e.g. "obfs2") that is obfuscating this connection. If no
+ * pluggable transports are used, it's NULL. */
+ char *ext_or_transport;
+
char *nickname; /**< Nickname of OR on other side (if any). */
tor_tls_t *tls; /**< TLS connection state. */
@@ -3428,6 +3478,8 @@ typedef struct {
char *User; /**< Name of user to run Tor as. */
char *Group; /**< Name of group to run Tor as. */
config_line_t *ORPort_lines; /**< Ports to listen on for OR connections. */
+ /** Ports to listen on for extended OR connections. */
+ config_line_t *ExtORPort_lines;
/** Ports to listen on for SOCKS connections. */
config_line_t *SocksPort_lines;
/** Ports to listen on for transparent pf/netfilter connections. */
@@ -3463,6 +3515,7 @@ typedef struct {
unsigned int ControlPort_set : 1;
unsigned int DirPort_set : 1;
unsigned int DNSPort_set : 1;
+ unsigned int ExtORPort_set : 1;
/**@}*/
int AssumeReachable; /**< Whether to publish our descriptor regardless. */
@@ -3502,6 +3555,9 @@ typedef struct {
/** List of TCP/IP addresses that transports should listen at. */
config_line_t *ServerTransportListenAddr;
+ /** List of options that must be passed to pluggable transports. */
+ config_line_t *ServerTransportOptions;
+
int BridgeRelay; /**< Boolean: are we acting as a bridge relay? We make
* this explicit so we can change how we behave in the
* future. */
@@ -3739,7 +3795,10 @@ typedef struct {
int CookieAuthentication; /**< Boolean: do we enable cookie-based auth for
* the control system? */
- char *CookieAuthFile; /**< Location of a cookie authentication file. */
+ char *CookieAuthFile; /**< Filesystem location of a ControlPort
+ * authentication cookie. */
+ char *ExtORPortCookieAuthFile; /**< Filesystem location of Extended
+ * ORPort authentication cookie. */
int CookieAuthFileGroupReadable; /**< Boolean: Is the CookieAuthFile g+r? */
int LeaveStreamsUnattached; /**< Boolean: Does Tor attach new streams to
* circuits itself (0), or does it expect a controller
@@ -3761,6 +3820,7 @@ typedef struct {
SAFELOG_SCRUB_ALL, SAFELOG_SCRUB_RELAY, SAFELOG_SCRUB_NONE
} SafeLogging_;
+ int Sandbox; /**< Boolean: should sandboxing be enabled? */
int SafeSocks; /**< Boolean: should we outright refuse application
* connections that use socks4 or socks5-with-local-dns? */
#define LOG_PROTOCOL_WARN (get_options()->ProtocolWarnings ? \
@@ -3780,7 +3840,8 @@ typedef struct {
int NumEntryGuards; /**< How many entry guards do we try to establish? */
int UseEntryGuardsAsDirGuards; /** Boolean: Do we try to get directory info
* from a smallish number of fixed nodes? */
- int NumDirectoryGuards; /**< How many dir guards do we try to establish? */
+ int NumDirectoryGuards; /**< How many dir guards do we try to establish?
+ * If 0, use value from NumEntryGuards. */
int RephistTrackTime; /**< How many seconds do we keep rephist info? */
int FastFirstHopPK; /**< If Tor believes it is safe, should we save a third
* of our PK time by sending CREATE_FAST cells? */
diff --git a/src/or/relay.c b/src/or/relay.c
index 2c2a88713..9a0fdd963 100644
--- a/src/or/relay.c
+++ b/src/or/relay.c
@@ -969,7 +969,7 @@ remap_event_helper(entry_connection_t *conn, const tor_addr_t *new_addr)
* <b>addr_out</b> to the address we're connected to, and <b>ttl_out</b> to
* the ttl of that address, in seconds, and return 0. On failure, return
* -1. */
-int
+STATIC int
connected_cell_parse(const relay_header_t *rh, const cell_t *cell,
tor_addr_t *addr_out, int *ttl_out)
{
@@ -2089,7 +2089,7 @@ packed_cell_free_unchecked(packed_cell_t *cell)
}
/** Allocate and return a new packed_cell_t. */
-static INLINE packed_cell_t *
+STATIC packed_cell_t *
packed_cell_new(void)
{
++total_cells_allocated;
@@ -2100,6 +2100,8 @@ packed_cell_new(void)
void
packed_cell_free(packed_cell_t *cell)
{
+ if (!cell)
+ return;
packed_cell_free_unchecked(cell);
}
@@ -2129,7 +2131,6 @@ packed_cell_copy(const cell_t *cell, int wide_circ_ids)
{
packed_cell_t *c = packed_cell_new();
cell_pack(c, cell, wide_circ_ids);
- c->next = NULL;
return c;
}
@@ -2137,14 +2138,7 @@ packed_cell_copy(const cell_t *cell, int wide_circ_ids)
void
cell_queue_append(cell_queue_t *queue, packed_cell_t *cell)
{
- if (queue->tail) {
- tor_assert(!queue->tail->next);
- queue->tail->next = cell;
- } else {
- queue->head = cell;
- }
- queue->tail = cell;
- cell->next = NULL;
+ TOR_SIMPLEQ_INSERT_TAIL(&queue->head, cell, next);
++queue->n;
}
@@ -2187,18 +2181,24 @@ cell_queue_append_packed_copy(cell_queue_t *queue, const cell_t *cell,
cell_queue_append(queue, copy);
}
+/** Initialize <b>queue</b> as an empty cell queue. */
+void
+cell_queue_init(cell_queue_t *queue)
+{
+ memset(queue, 0, sizeof(cell_queue_t));
+ TOR_SIMPLEQ_INIT(&queue->head);
+}
+
/** Remove and free every cell in <b>queue</b>. */
void
cell_queue_clear(cell_queue_t *queue)
{
- packed_cell_t *cell, *next;
- cell = queue->head;
- while (cell) {
- next = cell->next;
+ packed_cell_t *cell;
+ while ((cell = TOR_SIMPLEQ_FIRST(&queue->head))) {
+ TOR_SIMPLEQ_REMOVE_HEAD(&queue->head, next);
packed_cell_free_unchecked(cell);
- cell = next;
}
- queue->head = queue->tail = NULL;
+ TOR_SIMPLEQ_INIT(&queue->head);
queue->n = 0;
if (queue->insertion_times) {
while (queue->insertion_times->first) {
@@ -2212,17 +2212,13 @@ cell_queue_clear(cell_queue_t *queue)
/** Extract and return the cell at the head of <b>queue</b>; return NULL if
* <b>queue</b> is empty. */
-static INLINE packed_cell_t *
+STATIC packed_cell_t *
cell_queue_pop(cell_queue_t *queue)
{
- packed_cell_t *cell = queue->head;
+ packed_cell_t *cell = TOR_SIMPLEQ_FIRST(&queue->head);
if (!cell)
return NULL;
- queue->head = cell->next;
- if (cell == queue->tail) {
- tor_assert(!queue->head);
- queue->tail = NULL;
- }
+ TOR_SIMPLEQ_REMOVE_HEAD(&queue->head, next);
--queue->n;
return cell;
}
diff --git a/src/or/relay.h b/src/or/relay.h
index 69df7024b..e1b5e381e 100644
--- a/src/or/relay.h
+++ b/src/or/relay.h
@@ -51,6 +51,7 @@ size_t packed_cell_mem_cost(void);
/* For channeltls.c */
void packed_cell_free(packed_cell_t *cell);
+void cell_queue_init(cell_queue_t *queue);
void cell_queue_clear(cell_queue_t *queue);
void cell_queue_append(cell_queue_t *queue, packed_cell_t *cell);
void cell_queue_append_packed_copy(cell_queue_t *queue, const cell_t *cell,
@@ -75,11 +76,14 @@ void circuit_clear_cell_queue(circuit_t *circ, channel_t *chan);
void stream_choice_seed_weak_rng(void);
-#ifdef RELAY_PRIVATE
int relay_crypt(circuit_t *circ, cell_t *cell, cell_direction_t cell_direction,
crypt_path_t **layer_hint, char *recognized);
-int connected_cell_parse(const relay_header_t *rh, const cell_t *cell,
+
+#ifdef RELAY_PRIVATE
+STATIC int connected_cell_parse(const relay_header_t *rh, const cell_t *cell,
tor_addr_t *addr_out, int *ttl_out);
+STATIC packed_cell_t *packed_cell_new(void);
+STATIC packed_cell_t *cell_queue_pop(cell_queue_t *queue);
#endif
#endif
diff --git a/src/or/rendservice.c b/src/or/rendservice.c
index 7f771918c..fb56dc036 100644
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@ -1207,7 +1207,7 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
/* check for replay of PK-encrypted portion. */
replay = replaycache_add_test_and_elapsed(
intro_point->accepted_intro_rsa_parts,
- parsed_req->ciphertext, (int)parsed_req->ciphertext_len,
+ parsed_req->ciphertext, parsed_req->ciphertext_len,
&elapsed);
if (replay) {
@@ -1898,8 +1898,8 @@ rend_service_parse_intro_for_v3(
}
}
- /* Check that we actually have everything up to the timestamp */
- if (plaintext_len < (size_t)(ts_offset)) {
+ /* Check that we actually have everything up through the timestamp */
+ if (plaintext_len < (size_t)(ts_offset)+4) {
if (err_msg_out) {
tor_asprintf(err_msg_out,
"truncated plaintext of encrypted parted of "
@@ -1923,12 +1923,6 @@ rend_service_parse_intro_for_v3(
}
/*
- * Apparently we don't use the timestamp any more, but might as well copy
- * over just in case we ever care about it.
- */
- intro->u.v3.timestamp = ntohl(get_uint32(buf + ts_offset));
-
- /*
* From here on, the format is as in v2, so we call the v2 parser with
* adjusted buffer and length. We are 4 + ts_offset octets in, but the
* v2 parser expects to skip over a version byte at the start, so we
diff --git a/src/or/rendservice.h b/src/or/rendservice.h
index ff31ba6ed..caf88a3d6 100644
--- a/src/or/rendservice.h
+++ b/src/or/rendservice.h
@@ -56,8 +56,6 @@ struct rend_intro_cell_s {
uint16_t auth_len;
/* Auth data */
uint8_t *auth_data;
- /* timestamp */
- uint32_t timestamp;
/* Rendezvous point's IP address/port, identity digest and onion key */
extend_info_t *extend_info;
} v3;
diff --git a/src/or/replaycache.c b/src/or/replaycache.c
index 59b98489b..90f87c12d 100644
--- a/src/or/replaycache.c
+++ b/src/or/replaycache.c
@@ -63,9 +63,9 @@ replaycache_new(time_t horizon, time_t interval)
/** See documentation for replaycache_add_and_test()
*/
-int
+STATIC int
replaycache_add_and_test_internal(
- time_t present, replaycache_t *r, const void *data, int len,
+ time_t present, replaycache_t *r, const void *data, size_t len,
time_t *elapsed)
{
int rv = 0;
@@ -73,7 +73,7 @@ replaycache_add_and_test_internal(
time_t *access_time;
/* sanity check */
- if (present <= 0 || !r || !data || len <= 0) {
+ if (present <= 0 || !r || !data || len == 0) {
log_info(LD_BUG, "replaycache_add_and_test_internal() called with stupid"
" parameters; please fix this.");
goto done;
@@ -127,14 +127,13 @@ replaycache_add_and_test_internal(
/** See documentation for replaycache_scrub_if_needed()
*/
-void
+STATIC void
replaycache_scrub_if_needed_internal(time_t present, replaycache_t *r)
{
digestmap_iter_t *itr = NULL;
const char *digest;
void *valp;
time_t *access_time;
- char scrub_this;
/* sanity check */
if (!r || !(r->digests_seen)) {
@@ -152,20 +151,10 @@ replaycache_scrub_if_needed_internal(time_t present, replaycache_t *r)
/* okay, scrub time */
itr = digestmap_iter_init(r->digests_seen);
while (!digestmap_iter_done(itr)) {
- scrub_this = 0;
digestmap_iter_get(itr, &digest, &valp);
access_time = (time_t *)valp;
- if (access_time) {
- /* aged out yet? */
- if (*access_time < present - r->horizon) scrub_this = 1;
- } else {
- /* Buh? Get rid of it, anyway */
- log_info(LD_BUG, "replaycache_scrub_if_needed_internal() saw a NULL"
- " entry in the digestmap.");
- scrub_this = 1;
- }
-
- if (scrub_this) {
+ /* aged out yet? */
+ if (*access_time < present - r->horizon) {
/* Advance the iterator and remove this one */
itr = digestmap_iter_next_rmv(r->digests_seen, itr);
/* Free the value removed */
@@ -187,7 +176,7 @@ replaycache_scrub_if_needed_internal(time_t present, replaycache_t *r)
*/
int
-replaycache_add_and_test(replaycache_t *r, const void *data, int len)
+replaycache_add_and_test(replaycache_t *r, const void *data, size_t len)
{
return replaycache_add_and_test_internal(time(NULL), r, data, len, NULL);
}
@@ -198,7 +187,7 @@ replaycache_add_and_test(replaycache_t *r, const void *data, int len)
int
replaycache_add_test_and_elapsed(
- replaycache_t *r, const void *data, int len, time_t *elapsed)
+ replaycache_t *r, const void *data, size_t len, time_t *elapsed)
{
return replaycache_add_and_test_internal(time(NULL), r, data, len, elapsed);
}
diff --git a/src/or/replaycache.h b/src/or/replaycache.h
index de20cab62..cd713fe89 100644
--- a/src/or/replaycache.h
+++ b/src/or/replaycache.h
@@ -45,10 +45,10 @@ replaycache_t * replaycache_new(time_t horizon, time_t interval);
* testing. For everything else, use the wrappers below instead.
*/
-int replaycache_add_and_test_internal(
- time_t present, replaycache_t *r, const void *data, int len,
+STATIC int replaycache_add_and_test_internal(
+ time_t present, replaycache_t *r, const void *data, size_t len,
time_t *elapsed);
-void replaycache_scrub_if_needed_internal(
+STATIC void replaycache_scrub_if_needed_internal(
time_t present, replaycache_t *r);
#endif /* REPLAYCACHE_PRIVATE */
@@ -57,9 +57,9 @@ void replaycache_scrub_if_needed_internal(
* replaycache_t methods
*/
-int replaycache_add_and_test(replaycache_t *r, const void *data, int len);
+int replaycache_add_and_test(replaycache_t *r, const void *data, size_t len);
int replaycache_add_test_and_elapsed(
- replaycache_t *r, const void *data, int len, time_t *elapsed);
+ replaycache_t *r, const void *data, size_t len, time_t *elapsed);
void replaycache_scrub_if_needed(replaycache_t *r);
#endif
diff --git a/src/or/router.c b/src/or/router.c
index 6069da8f0..1063eda04 100644
--- a/src/or/router.c
+++ b/src/or/router.c
@@ -2249,7 +2249,7 @@ router_guess_address_from_dir_headers(uint32_t *guess)
* string describing the version of Tor and the operating system we're
* currently running on.
*/
-void
+STATIC void
get_platform_str(char *platform, size_t len)
{
tor_snprintf(platform, len, "Tor %s on %s",
diff --git a/src/or/router.h b/src/or/router.h
index 60095d087..1079ec78c 100644
--- a/src/or/router.h
+++ b/src/or/router.h
@@ -12,6 +12,8 @@
#ifndef TOR_ROUTER_H
#define TOR_ROUTER_H
+#include "testsupport.h"
+
crypto_pk_t *get_onion_key(void);
time_t get_onion_key_set_at(void);
void set_server_identity_key(crypto_pk_t *k);
@@ -146,7 +148,7 @@ smartlist_t *router_get_all_orports(const routerinfo_t *ri);
#ifdef ROUTER_PRIVATE
/* Used only by router.c and test.c */
-void get_platform_str(char *platform, size_t len);
+STATIC void get_platform_str(char *platform, size_t len);
#endif
#endif
diff --git a/src/or/routerlist.c b/src/or/routerlist.c
index a145ba716..46da17e03 100644
--- a/src/or/routerlist.c
+++ b/src/or/routerlist.c
@@ -1801,7 +1801,7 @@ router_get_advertised_bandwidth_capped(const routerinfo_t *router)
* doubles, convert them to uint64_t, and try to scale them linearly so as to
* much of the range of uint64_t. If <b>total_out</b> is provided, set it to
* the sum of all elements in the array _before_ scaling. */
-/* private */ void
+STATIC void
scale_array_elements_to_u64(u64_dbl_t *entries, int n_entries,
uint64_t *total_out)
{
@@ -1844,7 +1844,7 @@ gt_i64_timei(uint64_t a, uint64_t b)
* value, and return the index of that element. If all elements are 0, choose
* an index at random. Return -1 on error.
*/
-/* private */ int
+STATIC int
choose_array_element_by_weight(const u64_dbl_t *entries, int n_entries)
{
int i, i_chosen=-1, n_chosen=0;
diff --git a/src/or/routerlist.h b/src/or/routerlist.h
index ce0f0f2e3..0162297ca 100644
--- a/src/or/routerlist.h
+++ b/src/or/routerlist.h
@@ -11,6 +11,8 @@
#ifndef TOR_ROUTERLIST_H
#define TOR_ROUTERLIST_H
+#include "testsupport.h"
+
int get_n_authorities(dirinfo_type_t type);
int trusted_dirs_reload_certs(void);
@@ -206,9 +208,10 @@ typedef union u64_dbl_t {
double dbl;
} u64_dbl_t;
-int choose_array_element_by_weight(const u64_dbl_t *entries, int n_entries);
-void scale_array_elements_to_u64(u64_dbl_t *entries, int n_entries,
- uint64_t *total_out);
+STATIC int choose_array_element_by_weight(const u64_dbl_t *entries,
+ int n_entries);
+STATIC void scale_array_elements_to_u64(u64_dbl_t *entries, int n_entries,
+ uint64_t *total_out);
#endif
#endif
diff --git a/src/or/statefile.c b/src/or/statefile.c
index bcb7b0741..8736c35a2 100644
--- a/src/or/statefile.c
+++ b/src/or/statefile.c
@@ -4,6 +4,7 @@
* Copyright (c) 2007-2013, The Tor Project, Inc. */
/* See LICENSE for licensing information */
+#define STATEFILE_PRIVATE
#include "or.h"
#include "circuitstats.h"
#include "config.h"
@@ -117,8 +118,8 @@ static const config_format_t state_format = {
static or_state_t *global_state = NULL;
/** Return the persistent state struct for this Tor. */
-or_state_t *
-get_or_state(void)
+MOCK_IMPL(or_state_t *,
+get_or_state, (void))
{
tor_assert(global_state);
return global_state;
@@ -449,7 +450,7 @@ or_state_save(time_t now)
/** Return the config line for transport <b>transport</b> in the current state.
* Return NULL if there is no config line for <b>transport</b>. */
-static config_line_t *
+STATIC config_line_t *
get_transport_in_state_by_name(const char *transport)
{
or_state_t *or_state = get_or_state();
diff --git a/src/or/statefile.h b/src/or/statefile.h
index dcdee6c60..c1413ff95 100644
--- a/src/or/statefile.h
+++ b/src/or/statefile.h
@@ -7,7 +7,7 @@
#ifndef TOR_STATEFILE_H
#define TOR_STATEFILE_H
-or_state_t *get_or_state(void);
+MOCK_DECL(or_state_t *,get_or_state,(void));
int did_last_state_file_write_fail(void);
int or_state_save(time_t now);
@@ -18,5 +18,9 @@ int or_state_load(void);
int or_state_loaded(void);
void or_state_free_all(void);
+#ifdef STATEFILE_PRIVATE
+STATIC config_line_t *get_transport_in_state_by_name(const char *transport);
+#endif
+
#endif
diff --git a/src/or/transports.c b/src/or/transports.c
index 0afba24ea..f6bbbe81c 100644
--- a/src/or/transports.c
+++ b/src/or/transports.c
@@ -96,18 +96,15 @@
#include "router.h"
#include "statefile.h"
#include "entrynodes.h"
+#include "connection_or.h"
+#include "ext_orport.h"
static process_environment_t *
create_managed_proxy_environment(const managed_proxy_t *mp);
static INLINE int proxy_configuration_finished(const managed_proxy_t *mp);
-static void managed_proxy_destroy(managed_proxy_t *mp,
- int also_terminate_process);
-
static void handle_finished_proxy(managed_proxy_t *mp);
-static void configure_proxy(managed_proxy_t *mp);
-
static void parse_method_error(const char *line, int is_server_method);
#define parse_server_method_error(l) parse_method_error(l, 1)
#define parse_client_method_error(l) parse_method_error(l, 0)
@@ -137,7 +134,8 @@ static smartlist_t *transport_list = NULL;
SOCKS version <b>socks_ver</b>. */
static transport_t *
transport_new(const tor_addr_t *addr, uint16_t port,
- const char *name, int socks_ver)
+ const char *name, int socks_ver,
+ const char *extra_info_args)
{
transport_t *t = tor_malloc_zero(sizeof(transport_t));
@@ -145,6 +143,8 @@ transport_new(const tor_addr_t *addr, uint16_t port,
t->port = port;
t->name = tor_strdup(name);
t->socks_version = socks_ver;
+ if (extra_info_args)
+ t->extra_info_args = tor_strdup(extra_info_args);
return t;
}
@@ -157,6 +157,7 @@ transport_free(transport_t *transport)
return;
tor_free(transport->name);
+ tor_free(transport->extra_info_args);
tor_free(transport);
}
@@ -324,7 +325,7 @@ int
transport_add_from_config(const tor_addr_t *addr, uint16_t port,
const char *name, int socks_ver)
{
- transport_t *t = transport_new(addr, port, name, socks_ver);
+ transport_t *t = transport_new(addr, port, name, socks_ver, NULL);
int r = transport_add(t);
@@ -573,10 +574,8 @@ pt_configure_remaining_proxies(void)
/* If the proxy is not fully configured, try to configure it
futher. */
if (!proxy_configuration_finished(mp))
- configure_proxy(mp);
-
- if (proxy_configuration_finished(mp))
- at_least_a_proxy_config_finished = 1;
+ if (configure_proxy(mp) == 1)
+ at_least_a_proxy_config_finished = 1;
} SMARTLIST_FOREACH_END(mp);
@@ -588,10 +587,14 @@ pt_configure_remaining_proxies(void)
mark_my_descriptor_dirty("configured managed proxies");
}
-/** Attempt to continue configuring managed proxy <b>mp</b>. */
-static void
+/** Attempt to continue configuring managed proxy <b>mp</b>.
+ * Return 1 if the transport configuration finished, and return 0
+ * otherwise (if we still have more configuring to do for this
+ * proxy). */
+STATIC int
configure_proxy(managed_proxy_t *mp)
{
+ int configuration_finished = 0;
smartlist_t *proxy_output = NULL;
enum stream_status stream_status = 0;
@@ -601,7 +604,7 @@ configure_proxy(managed_proxy_t *mp)
mp->conf_state = PT_PROTO_FAILED_LAUNCH;
handle_finished_proxy(mp);
}
- return;
+ return 0;
}
tor_assert(mp->conf_state != PT_PROTO_INFANT);
@@ -633,13 +636,17 @@ configure_proxy(managed_proxy_t *mp)
done:
/* if the proxy finished configuring, exit the loop. */
- if (proxy_configuration_finished(mp))
+ if (proxy_configuration_finished(mp)) {
handle_finished_proxy(mp);
+ configuration_finished = 1;
+ }
if (proxy_output) {
SMARTLIST_FOREACH(proxy_output, char *, cp, tor_free(cp));
smartlist_free(proxy_output);
}
+
+ return configuration_finished;
}
/** Register server managed proxy <b>mp</b> transports to state */
@@ -694,7 +701,7 @@ register_proxy(const managed_proxy_t *mp)
}
/** Free memory allocated by managed proxy <b>mp</b>. */
-static void
+STATIC void
managed_proxy_destroy(managed_proxy_t *mp,
int also_terminate_process)
{
@@ -708,7 +715,8 @@ managed_proxy_destroy(managed_proxy_t *mp,
smartlist_free(mp->transports_to_launch);
/* remove it from the list of managed proxies */
- smartlist_remove(managed_proxy_list, mp);
+ if (managed_proxy_list)
+ smartlist_remove(managed_proxy_list, mp);
/* free the argv */
free_execve_args(mp->argv);
@@ -745,7 +753,6 @@ handle_finished_proxy(managed_proxy_t *mp)
}
unconfigured_proxies_n--;
- tor_assert(unconfigured_proxies_n >= 0);
}
/** Return true if the configuration of the managed proxy <b>mp</b> is
@@ -776,7 +783,7 @@ handle_methods_done(const managed_proxy_t *mp)
/** Handle a configuration protocol <b>line</b> received from a
* managed proxy <b>mp</b>. */
-void
+STATIC void
handle_proxy_line(const char *line, managed_proxy_t *mp)
{
log_info(LD_GENERAL, "Got a line from managed proxy '%s': (%s)",
@@ -877,7 +884,7 @@ handle_proxy_line(const char *line, managed_proxy_t *mp)
}
/** Parses an ENV-ERROR <b>line</b> and warns the user accordingly. */
-void
+STATIC void
parse_env_error(const char *line)
{
/* (Length of the protocol string) plus (a space) and (the first char of
@@ -893,7 +900,7 @@ parse_env_error(const char *line)
/** Handles a VERSION <b>line</b>. Updates the configuration protocol
* version in <b>mp</b>. */
-int
+STATIC int
parse_version(const char *line, managed_proxy_t *mp)
{
if (strlen(line) < (strlen(PROTO_NEG_SUCCESS) + 2)) {
@@ -934,14 +941,14 @@ parse_method_error(const char *line, int is_server)
/** Parses an SMETHOD <b>line</b> and if well-formed it registers the
* new transport in <b>mp</b>. */
-int
+STATIC int
parse_smethod_line(const char *line, managed_proxy_t *mp)
{
int r;
smartlist_t *items = NULL;
char *method_name=NULL;
-
+ char *args_string=NULL;
char *addrport=NULL;
tor_addr_t tor_addr;
char *address=NULL;
@@ -958,6 +965,9 @@ parse_smethod_line(const char *line, managed_proxy_t *mp)
goto err;
}
+ /* Example of legit SMETHOD line:
+ SMETHOD obfs2 0.0.0.0:25612 ARGS:secret=supersekrit,key=superkey */
+
tor_assert(!strcmp(smartlist_get(items,0),PROTO_SMETHOD));
method_name = smartlist_get(items,1);
@@ -985,7 +995,19 @@ parse_smethod_line(const char *line, managed_proxy_t *mp)
goto err;
}
- transport = transport_new(&tor_addr, port, method_name, PROXY_NONE);
+ if (smartlist_len(items) > 3) {
+ /* Seems like there are also some [options] in the SMETHOD line.
+ Let's see if we can parse them. */
+ char *options_string = smartlist_get(items, 3);
+ log_debug(LD_CONFIG, "Got options_string: %s", options_string);
+ if (!strcmpstart(options_string, "ARGS:")) {
+ args_string = options_string+strlen("ARGS:");
+ log_debug(LD_CONFIG, "Got ARGS: %s", args_string);
+ }
+ }
+
+ transport = transport_new(&tor_addr, port, method_name,
+ PROXY_NONE, args_string);
if (!transport)
goto err;
@@ -1011,7 +1033,7 @@ parse_smethod_line(const char *line, managed_proxy_t *mp)
/** Parses a CMETHOD <b>line</b>, and if well-formed it registers
* the new transport in <b>mp</b>. */
-int
+STATIC int
parse_cmethod_line(const char *line, managed_proxy_t *mp)
{
int r;
@@ -1077,7 +1099,7 @@ parse_cmethod_line(const char *line, managed_proxy_t *mp)
goto err;
}
- transport = transport_new(&tor_addr, port, method_name, socks_ver);
+ transport = transport_new(&tor_addr, port, method_name, socks_ver, NULL);
if (!transport)
goto err;
@@ -1100,6 +1122,50 @@ parse_cmethod_line(const char *line, managed_proxy_t *mp)
return r;
}
+/** Return a newly allocated string that tor should place in
+ * TOR_PT_SERVER_TRANSPORT_OPTIONS while configuring the server
+ * manged proxy in <b>mp</b>. Return NULL if no such options are found. */
+STATIC char *
+get_transport_options_for_server_proxy(const managed_proxy_t *mp)
+{
+ char *options_string = NULL;
+ smartlist_t *string_sl = smartlist_new();
+
+ tor_assert(mp->is_server);
+
+ /** Loop over the transports of the proxy. If we have options for
+ any of them, format them appropriately and place them in our
+ smartlist. Finally, join our smartlist to get the final
+ string. */
+ SMARTLIST_FOREACH_BEGIN(mp->transports_to_launch, const char *, transport) {
+ smartlist_t *options_tmp_sl = NULL;
+ options_tmp_sl = get_options_for_server_transport(transport);
+ if (!options_tmp_sl)
+ continue;
+
+ /** Loop over the options of this transport, escape them, and
+ place them in the smartlist. */
+ SMARTLIST_FOREACH_BEGIN(options_tmp_sl, const char *, options) {
+ char *escaped_opts = tor_escape_str_for_pt_args(options, ":;\\");
+ smartlist_add_asprintf(string_sl, "%s:%s",
+ transport, escaped_opts);
+ tor_free(escaped_opts);
+ } SMARTLIST_FOREACH_END(options);
+
+ SMARTLIST_FOREACH(options_tmp_sl, char *, c, tor_free(c));
+ smartlist_free(options_tmp_sl);
+ } SMARTLIST_FOREACH_END(transport);
+
+ if (smartlist_len(string_sl)) {
+ options_string = smartlist_join_strings(string_sl, ";", 0, NULL);
+ }
+
+ SMARTLIST_FOREACH(string_sl, char *, t, tor_free(t));
+ smartlist_free(string_sl);
+
+ return options_string;
+}
+
/** Return the string that tor should place in TOR_PT_SERVER_BINDADDR
* while configuring the server managed proxy in <b>mp</b>. The
* string is stored in the heap, and it's the the responsibility of
@@ -1134,6 +1200,8 @@ get_bindaddr_for_server_proxy(const managed_proxy_t *mp)
static process_environment_t *
create_managed_proxy_environment(const managed_proxy_t *mp)
{
+ const or_options_t *options = get_options();
+
/* Environment variables to be added to or set in mp's environment. */
smartlist_t *envs = smartlist_new();
/* XXXX The next time someone touches this code, shorten the name of
@@ -1181,13 +1249,39 @@ create_managed_proxy_environment(const managed_proxy_t *mp)
tor_free(bindaddr_tmp);
}
+ {
+ char *server_transport_options =
+ get_transport_options_for_server_proxy(mp);
+ if (server_transport_options) {
+ smartlist_add_asprintf(envs, "TOR_PT_SERVER_TRANSPORT_OPTIONS=%s",
+ server_transport_options);
+ tor_free(server_transport_options);
+ }
+ }
+
/* XXX024 Remove the '=' here once versions of obfsproxy which
* assert that this env var exists are sufficiently dead.
*
* (If we remove this line entirely, some joker will stick this
* variable in Tor's environment and crash PTs that try to parse
* it even when not run in server mode.) */
- smartlist_add(envs, tor_strdup("TOR_PT_EXTENDED_SERVER_PORT="));
+
+ if (options->ExtORPort_lines) {
+ char *ext_or_addrport_tmp =
+ get_first_listener_addrport_string(CONN_TYPE_EXT_OR_LISTENER);
+ char *cookie_file_loc = get_ext_or_auth_cookie_file_name();
+
+ smartlist_add_asprintf(envs, "TOR_PT_EXTENDED_SERVER_PORT=%s",
+ ext_or_addrport_tmp);
+ smartlist_add_asprintf(envs, "TOR_PT_AUTH_COOKIE_FILE=%s",
+ cookie_file_loc);
+
+ tor_free(ext_or_addrport_tmp);
+ tor_free(cookie_file_loc);
+
+ } else {
+ smartlist_add_asprintf(envs, "TOR_PT_EXTENDED_SERVER_PORT=");
+ }
}
SMARTLIST_FOREACH_BEGIN(envs, const char *, env_var) {
@@ -1211,7 +1305,7 @@ create_managed_proxy_environment(const managed_proxy_t *mp)
* <b>proxy_argv</b>.
*
* Requires that proxy_argv have at least one element. */
-static managed_proxy_t *
+STATIC managed_proxy_t *
managed_proxy_create(const smartlist_t *transport_list,
char **proxy_argv, int is_server)
{
@@ -1385,6 +1479,8 @@ pt_get_extra_info_descriptor_string(void)
tor_assert(mp->transports);
SMARTLIST_FOREACH_BEGIN(mp->transports, const transport_t *, t) {
+ char *transport_args = NULL;
+
/* If the transport proxy returned "0.0.0.0" as its address, and
* we know our external IP address, use it. Otherwise, use the
* returned address. */
@@ -1400,9 +1496,16 @@ pt_get_extra_info_descriptor_string(void)
addrport = fmt_addrport(&t->addr, t->port);
}
+ /* If this transport has any arguments with it, prepend a space
+ to them so that we can add them to the transport line. */
+ if (t->extra_info_args)
+ tor_asprintf(&transport_args, " %s", t->extra_info_args);
+
smartlist_add_asprintf(string_chunks,
- "transport %s %s",
- t->name, addrport);
+ "transport %s %s%s",
+ t->name, addrport,
+ transport_args ? transport_args : "");
+ tor_free(transport_args);
} SMARTLIST_FOREACH_END(t);
} SMARTLIST_FOREACH_END(mp);
@@ -1440,7 +1543,7 @@ pt_stringify_socks_args(const smartlist_t *socks_args)
SMARTLIST_FOREACH_BEGIN(socks_args, const char *, s) {
/* Escape ';' and '\'. */
- escaped_string = tor_escape_str_for_socks_arg(s);
+ escaped_string = tor_escape_str_for_pt_args(s, ";\\");
if (!escaped_string)
goto done;
diff --git a/src/or/transports.h b/src/or/transports.h
index 4a5498cb5..7b524f207 100644
--- a/src/or/transports.h
+++ b/src/or/transports.h
@@ -25,6 +25,9 @@ typedef struct transport_t {
/** Boolean: We are re-parsing our transport list, and we are going to remove
* this one if we don't find it in the list of configured transports. */
unsigned marked_for_removal : 1;
+ /** Arguments for this transport that must be written to the
+ extra-info descriptor. */
+ char *extra_info_args;
} transport_t;
void mark_transport_list(void);
@@ -104,12 +107,21 @@ typedef struct {
smartlist_t *transports;
} managed_proxy_t;
-int parse_cmethod_line(const char *line, managed_proxy_t *mp);
-int parse_smethod_line(const char *line, managed_proxy_t *mp);
+STATIC int parse_cmethod_line(const char *line, managed_proxy_t *mp);
+STATIC int parse_smethod_line(const char *line, managed_proxy_t *mp);
-int parse_version(const char *line, managed_proxy_t *mp);
-void parse_env_error(const char *line);
-void handle_proxy_line(const char *line, managed_proxy_t *mp);
+STATIC int parse_version(const char *line, managed_proxy_t *mp);
+STATIC void parse_env_error(const char *line);
+STATIC void handle_proxy_line(const char *line, managed_proxy_t *mp);
+STATIC char *get_transport_options_for_server_proxy(const managed_proxy_t *mp);
+
+STATIC void managed_proxy_destroy(managed_proxy_t *mp,
+ int also_terminate_process);
+
+STATIC managed_proxy_t *managed_proxy_create(const smartlist_t *transport_list,
+ char **proxy_argv, int is_server);
+
+STATIC int configure_proxy(managed_proxy_t *mp);
#endif