Merge branch 'orconn-tracker_squashed'

This commit is contained in:
Nick Mathewson
2018-12-21 14:22:11 -05:00
42 changed files with 1845 additions and 119 deletions
+11
View File
@@ -0,0 +1,11 @@
o Major features (bootstrap):
- Report the first connection to a relay as the earliest phases of
bootstrap progress, regardless of whether it's a connection for
building application circuits. This allows finer-grained
reporting of early progress than previously possible with the
improvements of ticket 27169. Closes tickets 27167 and 27103.
Addresses ticket 27308.
- Separately report the intermediate stage of having connected to
a proxy or pluggable transport, versus succesfully using that
proxy or pluggable transport to connect to a relay. Closes
tickets 27100 and 28884.
+1 -1
View File
@@ -678,7 +678,7 @@ GENERAL OPTIONS
The currently recognized domains are: general, crypto, net, config, fs,
protocol, mm, http, app, control, circ, rend, bug, dir, dirserv, or, edge,
acct, hist, handshake, heartbeat, channel, sched, guard, consdiff, dos,
process, and pt.
process, pt, and btrack.
Domain names are case-insensitive. +
+
For example, "`Log [handshake]debug [~net,~mm]info notice stdout`" sends
+7
View File
@@ -8,6 +8,9 @@
#include "lib/cc/compat_compiler.h"
#include "lib/cc/torint.h"
#include "core/or/ocirc_event_sys.h"
#include "core/or/orconn_event_sys.h"
#include "feature/control/btrack_sys.h"
#include "lib/compress/compress_sys.h"
#include "lib/crypt_ops/crypto_sys.h"
#include "lib/err/torerr_sys.h"
@@ -37,6 +40,10 @@ const subsys_fns_t *tor_subsystems[] = {
&sys_crypto, /* -60 */
&sys_tortls, /* -50 */
&sys_process, /* -35 */
&sys_orconn_event, /* -33 */
&sys_ocirc_event, /* -32 */
&sys_btrack, /* -30 */
};
const unsigned n_tor_subsystems = ARRAY_LENGTH(tor_subsystems);
+16
View File
@@ -39,6 +39,8 @@ LIBTOR_APP_A_SOURCES = \
src/core/or/connection_or.c \
src/core/or/dos.c \
src/core/or/onion.c \
src/core/or/ocirc_event.c \
src/core/or/orconn_event.c \
src/core/or/policies.c \
src/core/or/protover.c \
src/core/or/protover_rust.c \
@@ -61,6 +63,11 @@ LIBTOR_APP_A_SOURCES = \
src/feature/client/dnsserv.c \
src/feature/client/entrynodes.c \
src/feature/client/transports.c \
src/feature/control/btrack.c \
src/feature/control/btrack_circuit.c \
src/feature/control/btrack_orconn.c \
src/feature/control/btrack_orconn_cevent.c \
src/feature/control/btrack_orconn_maps.c \
src/feature/control/control.c \
src/feature/control/control_bootstrap.c \
src/feature/control/fmt_serverstatus.c \
@@ -238,10 +245,14 @@ noinst_HEADERS += \
src/core/or/listener_connection_st.h \
src/core/or/onion.h \
src/core/or/or.h \
src/core/or/orconn_event.h \
src/core/or/orconn_event_sys.h \
src/core/or/or_circuit_st.h \
src/core/or/or_connection_st.h \
src/core/or/or_handshake_certs_st.h \
src/core/or/or_handshake_state_st.h \
src/core/or/ocirc_event.h \
src/core/or/ocirc_event_sys.h \
src/core/or/origin_circuit_st.h \
src/core/or/policies.h \
src/core/or/port_cfg_st.h \
@@ -268,6 +279,11 @@ noinst_HEADERS += \
src/feature/client/dnsserv.h \
src/feature/client/entrynodes.h \
src/feature/client/transports.h \
src/feature/control/btrack_circuit.h \
src/feature/control/btrack_orconn.h \
src/feature/control/btrack_orconn_cevent.h \
src/feature/control/btrack_orconn_maps.h \
src/feature/control/btrack_sys.h \
src/feature/control/control.h \
src/feature/control/control_connection_st.h \
src/feature/control/fmt_serverstatus.h \
+1 -1
View File
@@ -1875,7 +1875,7 @@ connection_init_accepted_conn(connection_t *conn,
/* 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);
connection_or_event_status(TO_OR_CONN(conn), OR_CONN_EVENT_NEW, 0);
rv = connection_tls_start_handshake(TO_OR_CONN(conn), 1);
if (rv < 0) {
connection_or_close_for_error(TO_OR_CONN(conn), 0);
-3
View File
@@ -950,7 +950,6 @@ channel_tls_listener_describe_transport_method(channel_listener_t *chan_l)
void
channel_tls_handle_state_change_on_orconn(channel_tls_t *chan,
or_connection_t *conn,
uint8_t old_state,
uint8_t state)
{
channel_t *base_chan;
@@ -959,8 +958,6 @@ channel_tls_handle_state_change_on_orconn(channel_tls_t *chan,
tor_assert(conn);
tor_assert(conn->chan == chan);
tor_assert(chan->conn == conn);
/* Shut the compiler up without triggering -Wtautological-compare */
(void)old_state;
base_chan = TLS_CHAN_TO_BASE(chan);
-1
View File
@@ -49,7 +49,6 @@ channel_tls_t * channel_tls_from_base(channel_t *chan);
void channel_tls_handle_cell(cell_t *cell, or_connection_t *conn);
void channel_tls_handle_state_change_on_orconn(channel_tls_t *chan,
or_connection_t *conn,
uint8_t old_state,
uint8_t state);
void channel_tls_handle_var_cell(var_cell_t *var_cell,
or_connection_t *conn);
+28 -4
View File
@@ -26,6 +26,7 @@
**/
#define CIRCUITBUILD_PRIVATE
#define OCIRC_EVENT_PRIVATE
#include "core/or/or.h"
#include "app/config/config.h"
@@ -46,6 +47,7 @@
#include "core/or/connection_edge.h"
#include "core/or/connection_or.h"
#include "core/or/onion.h"
#include "core/or/ocirc_event.h"
#include "core/or/policies.h"
#include "core/or/relay.h"
#include "feature/client/bridges.h"
@@ -492,7 +494,7 @@ circuit_establish_circuit(uint8_t purpose, extend_info_t *exit_ei, int flags)
return NULL;
}
control_event_circuit_status(circ, CIRC_EVENT_LAUNCHED, 0);
circuit_event_status(circ, CIRC_EVENT_LAUNCHED, 0);
if ((err_reason = circuit_handle_first_hop(circ)) < 0) {
circuit_mark_for_close(TO_CIRCUIT(circ), -err_reason);
@@ -508,6 +510,28 @@ origin_circuit_get_guard_state(origin_circuit_t *circ)
return circ->guard_state;
}
/**
* Helper function to publish a channel association message
*
* circuit_handle_first_hop() calls this to notify subscribers about a
* channel launch event, which associates a circuit with a channel.
* This doesn't always correspond to an assignment of the circuit's
* n_chan field, because that seems to be only for fully-open
* channels.
**/
static void
circuit_chan_publish(const origin_circuit_t *circ, const channel_t *chan)
{
ocirc_event_msg_t msg;
msg.type = OCIRC_MSGTYPE_CHAN;
msg.u.chan.gid = circ->global_identifier;
msg.u.chan.chan = chan->global_identifier;
msg.u.chan.onehop = circ->build_state->onehop_tunnel;
ocirc_event_publish(&msg);
}
/** Start establishing the first hop of our circuit. Figure out what
* OR we should connect to, and if necessary start the connection to
* it. If we're already connected, then send the 'create' cell.
@@ -559,8 +583,6 @@ circuit_handle_first_hop(origin_circuit_t *circ)
circ->base_.n_hop = extend_info_dup(firsthop->extend_info);
if (should_launch) {
if (circ->build_state->onehop_tunnel)
control_event_bootstrap(BOOTSTRAP_STATUS_CONN_DIR, 0);
n_chan = channel_connect_for_circuit(
&firsthop->extend_info->addr,
firsthop->extend_info->port,
@@ -570,6 +592,7 @@ circuit_handle_first_hop(origin_circuit_t *circ)
log_info(LD_CIRC,"connect to firsthop failed. Closing.");
return -END_CIRC_REASON_CONNECTFAILED;
}
circuit_chan_publish(circ, n_chan);
}
log_debug(LD_CIRC,"connecting in progress (or finished). Good.");
@@ -581,6 +604,7 @@ circuit_handle_first_hop(origin_circuit_t *circ)
} else { /* it's already open. use it. */
tor_assert(!circ->base_.n_hop);
circ->base_.n_chan = n_chan;
circuit_chan_publish(circ, n_chan);
log_debug(LD_CIRC,"Conn open. Delivering first onion skin.");
if ((err_reason = circuit_send_next_onion_skin(circ)) < 0) {
log_info(LD_CIRC,"circuit_send_next_onion_skin failed.");
@@ -1416,7 +1440,7 @@ circuit_finish_handshake(origin_circuit_t *circ,
hop->state = CPATH_STATE_OPEN;
log_info(LD_CIRC,"Finished building circuit hop:");
circuit_log_path(LOG_INFO,LD_CIRC,circ);
control_event_circuit_status(circ, CIRC_EVENT_EXTENDED, 0);
circuit_event_status(circ, CIRC_EVENT_EXTENDED, 0);
return 0;
}
+56 -1
View File
@@ -51,6 +51,7 @@
* logic, which was originally circuit-focused.
**/
#define CIRCUITLIST_PRIVATE
#define OCIRC_EVENT_PRIVATE
#include "lib/cc/torint.h" /* TOR_PRIuSZ */
#include "core/or/or.h"
@@ -96,6 +97,9 @@
#include "lib/compress/compress_zstd.h"
#include "lib/buf/buffers.h"
#define OCIRC_EVENT_PRIVATE
#include "core/or/ocirc_event.h"
#include "ht.h"
#include "core/or/cpath_build_state_st.h"
@@ -481,6 +485,56 @@ circuit_set_n_circid_chan(circuit_t *circ, circid_t id,
}
}
/**
* Helper function to publish a message about events on an origin circuit
*
* Publishes a message to subscribers of origin circuit events, and
* sends the control event.
**/
int
circuit_event_status(origin_circuit_t *circ, circuit_status_event_t tp,
int reason_code)
{
ocirc_event_msg_t msg;
tor_assert(circ);
msg.type = OCIRC_MSGTYPE_CEVENT;
msg.u.cevent.gid = circ->global_identifier;
msg.u.cevent.evtype = tp;
msg.u.cevent.reason = reason_code;
msg.u.cevent.onehop = circ->build_state->onehop_tunnel;
ocirc_event_publish(&msg);
return control_event_circuit_status(circ, tp, reason_code);
}
/**
* Helper function to publish a state change message
*
* circuit_set_state() calls this to notify subscribers about a change
* of the state of an origin circuit.
**/
static void
circuit_state_publish(const circuit_t *circ)
{
ocirc_event_msg_t msg;
const origin_circuit_t *ocirc;
if (!CIRCUIT_IS_ORIGIN(circ))
return;
ocirc = CONST_TO_ORIGIN_CIRCUIT(circ);
/* Only inbound OR circuits can be in this state, not origin circuits. */
tor_assert(circ->state != CIRCUIT_STATE_ONIONSKIN_PENDING);
msg.type = OCIRC_MSGTYPE_STATE;
msg.u.state.gid = ocirc->global_identifier;
msg.u.state.state = circ->state;
msg.u.state.onehop = ocirc->build_state->onehop_tunnel;
ocirc_event_publish(&msg);
}
/** Change the state of <b>circ</b> to <b>state</b>, adding it to or removing
* it from lists as appropriate. */
void
@@ -510,6 +564,7 @@ circuit_set_state(circuit_t *circ, uint8_t state)
if (state == CIRCUIT_STATE_GUARD_WAIT || state == CIRCUIT_STATE_OPEN)
tor_assert(!circ->n_chan_create_cell);
circ->state = state;
circuit_state_publish(circ);
}
/** Append to <b>out</b> all circuits in state CHAN_WAIT waiting for
@@ -2270,7 +2325,7 @@ circuit_about_to_free(circuit_t *circ)
smartlist_remove(circuits_pending_other_guards, circ);
}
if (CIRCUIT_IS_ORIGIN(circ)) {
control_event_circuit_status(TO_ORIGIN_CIRCUIT(circ),
circuit_event_status(TO_ORIGIN_CIRCUIT(circ),
(circ->state == CIRCUIT_STATE_OPEN ||
circ->state == CIRCUIT_STATE_GUARD_WAIT) ?
CIRC_EVENT_CLOSED:CIRC_EVENT_FAILED,
+3
View File
@@ -14,6 +14,7 @@
#include "lib/testsupport/testsupport.h"
#include "feature/hs/hs_ident.h"
#include "core/or/ocirc_event.h"
/** Circuit state: I'm the origin, still haven't done all my handshakes. */
#define CIRCUIT_STATE_BUILDING 0
@@ -184,6 +185,8 @@ void channel_mark_circid_unusable(channel_t *chan, circid_t id);
void channel_mark_circid_usable(channel_t *chan, circid_t id);
time_t circuit_id_when_marked_unusable_on_channel(circid_t circ_id,
channel_t *chan);
int circuit_event_status(origin_circuit_t *circ, circuit_status_event_t tp,
int reason_code);
void circuit_set_state(circuit_t *circ, uint8_t state);
void circuit_close_all_marked(void);
int32_t circuit_initial_package_window(void);
+3 -3
View File
@@ -639,9 +639,9 @@ circuit_build_times_rewind_history(circuit_build_times_t *cbt, int n)
void
circuit_build_times_mark_circ_as_measurement_only(origin_circuit_t *circ)
{
control_event_circuit_status(circ,
CIRC_EVENT_FAILED,
END_CIRC_REASON_TIMEOUT);
circuit_event_status(circ,
CIRC_EVENT_FAILED,
END_CIRC_REASON_TIMEOUT);
circuit_change_purpose(TO_CIRCUIT(circ),
CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT);
/* Record this event to check for too many timeouts
+1 -1
View File
@@ -1664,7 +1664,7 @@ circuit_testing_failed(origin_circuit_t *circ, int at_last_hop)
void
circuit_has_opened(origin_circuit_t *circ)
{
control_event_circuit_status(circ, CIRC_EVENT_BUILT, 0);
circuit_event_status(circ, CIRC_EVENT_BUILT, 0);
/* Remember that this circuit has finished building. Now if we start
* it building again later (e.g. by extending it), we will know not
+63 -18
View File
@@ -29,6 +29,7 @@
*/
#define TOR_CHANNEL_INTERNAL_
#define CONNECTION_OR_PRIVATE
#define ORCONN_EVENT_PRIVATE
#include "core/or/channel.h"
#include "core/or/channeltls.h"
#include "core/or/circuitbuild.h"
@@ -79,6 +80,8 @@
#include "lib/tls/tortls.h"
#include "lib/tls/x509.h"
#include "core/or/orconn_event.h"
static int connection_tls_finish_handshake(or_connection_t *conn);
static int connection_or_launch_v3_or_handshake(or_connection_t *conn);
static int connection_or_process_cells_from_inbuf(or_connection_t *conn);
@@ -401,6 +404,49 @@ connection_or_report_broken_states(int severity, int domain)
smartlist_free(items);
}
/**
* Helper function to publish an OR connection status event
*
* Publishes a messages to subscribers of ORCONN messages, and sends
* the control event.
**/
void
connection_or_event_status(or_connection_t *conn, or_conn_status_event_t tp,
int reason)
{
orconn_event_msg_t msg;
msg.type = ORCONN_MSGTYPE_STATUS;
msg.u.status.gid = conn->base_.global_identifier;
msg.u.status.status = tp;
msg.u.status.reason = reason;
orconn_event_publish(&msg);
control_event_or_conn_status(conn, tp, reason);
}
/**
* Helper function to publish a state change message
*
* connection_or_change_state() calls this to notify subscribers about
* a change of an OR connection state.
**/
static void
connection_or_state_publish(const or_connection_t *conn, uint8_t state)
{
orconn_event_msg_t msg;
msg.type = ORCONN_MSGTYPE_STATE;
msg.u.state.gid = conn->base_.global_identifier;
msg.u.state.proxy_type = conn->proxy_type;
msg.u.state.state = state;
if (conn->chan) {
msg.u.state.chan = TLS_CHAN_TO_BASE(conn->chan)->global_identifier;
} else {
msg.u.state.chan = 0;
}
orconn_event_publish(&msg);
}
/** Call this to change or_connection_t states, so the owning channel_tls_t can
* be notified.
*/
@@ -408,16 +454,13 @@ connection_or_report_broken_states(int severity, int domain)
static void
connection_or_change_state(or_connection_t *conn, uint8_t state)
{
uint8_t old_state;
tor_assert(conn);
old_state = conn->base_.state;
conn->base_.state = state;
connection_or_state_publish(conn, state);
if (conn->chan)
channel_tls_handle_state_change_on_orconn(conn->chan, conn,
old_state, state);
channel_tls_handle_state_change_on_orconn(conn->chan, conn, state);
}
/** Return the number of circuits using an or_connection_t; this used to
@@ -708,8 +751,6 @@ connection_or_finished_connecting(or_connection_t *or_conn)
log_debug(LD_HANDSHAKE,"OR connect() to router at %s:%u finished.",
conn->address,conn->port);
control_event_bootstrap(BOOTSTRAP_STATUS_HANDSHAKE, 0);
control_event_boot_first_orconn();
if (proxy_type != PROXY_NONE) {
/* start proxy handshake */
@@ -759,8 +800,8 @@ connection_or_about_to_close(or_connection_t *or_conn)
entry_guard_chan_failed(TLS_CHAN_TO_BASE(or_conn->chan));
if (conn->state >= OR_CONN_STATE_TLS_HANDSHAKING) {
int reason = tls_error_to_orconn_end_reason(or_conn->tls_error);
control_event_or_conn_status(or_conn, OR_CONN_EVENT_FAILED,
reason);
connection_or_event_status(or_conn, OR_CONN_EVENT_FAILED,
reason);
if (!authdir_mode_tests_reachability(options))
control_event_bootstrap_prob_or(
orconn_end_reason_to_control_string(reason),
@@ -770,10 +811,10 @@ connection_or_about_to_close(or_connection_t *or_conn)
} else if (conn->hold_open_until_flushed) {
/* We only set hold_open_until_flushed when we're intentionally
* closing a connection. */
control_event_or_conn_status(or_conn, OR_CONN_EVENT_CLOSED,
connection_or_event_status(or_conn, OR_CONN_EVENT_CLOSED,
tls_error_to_orconn_end_reason(or_conn->tls_error));
} else if (!tor_digest_is_zero(or_conn->identity_digest)) {
control_event_or_conn_status(or_conn, OR_CONN_EVENT_CLOSED,
connection_or_event_status(or_conn, OR_CONN_EVENT_CLOSED,
tls_error_to_orconn_end_reason(or_conn->tls_error));
}
}
@@ -1365,7 +1406,7 @@ void
connection_or_connect_failed(or_connection_t *conn,
int reason, const char *msg)
{
control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED, reason);
connection_or_event_status(conn, OR_CONN_EVENT_FAILED, reason);
if (!authdir_mode_tests_reachability(get_options()))
control_event_bootstrap_prob_or(msg, reason, conn);
note_or_connect_failed(conn);
@@ -1472,9 +1513,6 @@ connection_or_connect, (const tor_addr_t *_addr, uint16_t port,
return NULL;
}
connection_or_change_state(conn, OR_CONN_STATE_CONNECTING);
control_event_or_conn_status(conn, OR_CONN_EVENT_LAUNCHED, 0);
conn->is_outgoing = 1;
/* If we are using a proxy server, find it and use it. */
@@ -1486,7 +1524,14 @@ connection_or_connect, (const tor_addr_t *_addr, uint16_t port,
port = proxy_port;
conn->base_.proxy_state = PROXY_INFANT;
}
connection_or_change_state(conn, OR_CONN_STATE_CONNECTING);
connection_or_event_status(conn, OR_CONN_EVENT_LAUNCHED, 0);
} else {
/* This duplication of state change calls is necessary in case we
* run into an error condition below */
connection_or_change_state(conn, OR_CONN_STATE_CONNECTING);
connection_or_event_status(conn, OR_CONN_EVENT_LAUNCHED, 0);
/* get_proxy_addrport() might fail if we have a Bridge line that
references a transport, but no ClientTransportPlugin lines
defining its transport proxy. If this is the case, let's try to
@@ -1982,8 +2027,8 @@ connection_or_client_learned_peer_id(or_connection_t *conn,
/* Tell the new guard API about the channel failure */
entry_guard_chan_failed(TLS_CHAN_TO_BASE(conn->chan));
control_event_or_conn_status(conn, OR_CONN_EVENT_FAILED,
END_OR_CONN_REASON_OR_IDENTITY);
connection_or_event_status(conn, OR_CONN_EVENT_FAILED,
END_OR_CONN_REASON_OR_IDENTITY);
if (!authdir_mode_tests_reachability(options))
control_event_bootstrap_prob_or(
"Unexpected identity in router certificate",
@@ -2223,7 +2268,7 @@ int
connection_or_set_state_open(or_connection_t *conn)
{
connection_or_change_state(conn, OR_CONN_STATE_OPEN);
control_event_or_conn_status(conn, OR_CONN_EVENT_CONNECTED, 0);
connection_or_event_status(conn, OR_CONN_EVENT_CONNECTED, 0);
/* Link protocol 3 appeared in Tor 0.2.3.6-alpha, so any connection
* that uses an earlier link protocol should not be treated as a relay. */
+4 -26
View File
@@ -17,32 +17,7 @@ struct ed25519_keypair_t;
or_connection_t *TO_OR_CONN(connection_t *);
#define OR_CONN_STATE_MIN_ 1
/** State for a connection to an OR: waiting for connect() to finish. */
#define OR_CONN_STATE_CONNECTING 1
/** State for a connection to an OR: waiting for proxy handshake to complete */
#define OR_CONN_STATE_PROXY_HANDSHAKING 2
/** State for an OR connection client: SSL is handshaking, not done
* yet. */
#define OR_CONN_STATE_TLS_HANDSHAKING 3
/** State for a connection to an OR: We're doing a second SSL handshake for
* renegotiation purposes. (V2 handshake only.) */
#define OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING 4
/** State for a connection at an OR: We're waiting for the client to
* renegotiate (to indicate a v2 handshake) or send a versions cell (to
* indicate a v3 handshake) */
#define OR_CONN_STATE_TLS_SERVER_RENEGOTIATING 5
/** State for an OR connection: We're done with our SSL handshake, we've done
* renegotiation, but we haven't yet negotiated link protocol versions and
* sent a netinfo cell. */
#define OR_CONN_STATE_OR_HANDSHAKING_V2 6
/** State for an OR connection: We're done with our SSL handshake, but we
* haven't yet negotiated link protocol versions, done a V3 handshake, and
* sent a netinfo cell. */
#define OR_CONN_STATE_OR_HANDSHAKING_V3 7
/** State for an OR connection: Ready to send/receive cells. */
#define OR_CONN_STATE_OPEN 8
#define OR_CONN_STATE_MAX_ 8
#include "core/or/orconn_event.h"
void connection_or_clear_identity(or_connection_t *conn);
void connection_or_clear_identity_map(void);
@@ -81,6 +56,9 @@ MOCK_DECL(void,connection_or_close_for_error,
void connection_or_report_broken_states(int severity, int domain);
void connection_or_event_status(or_connection_t *conn,
or_conn_status_event_t tp, int reason);
MOCK_DECL(int,connection_tls_start_handshake,(or_connection_t *conn,
int receiving));
int connection_tls_continue_handshake(or_connection_t *conn);
+84
View File
@@ -0,0 +1,84 @@
/* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file ocirc_event.c
* \brief Publish state change messages for origin circuits
*
* Implements a basic publish-subscribe framework for messages about
* the state of origin circuits. The publisher calls the subscriber
* callback functions synchronously.
*
* Although the synchronous calls might not simplify the call graph,
* this approach improves data isolation because the publisher doesn't
* need knowledge about the internals of subscribing subsystems. It
* also avoids race conditions that might occur in asynchronous
* frameworks.
**/
#include "core/or/or.h"
#define OCIRC_EVENT_PRIVATE
#include "core/or/cpath_build_state_st.h"
#include "core/or/ocirc_event.h"
#include "core/or/ocirc_event_sys.h"
#include "core/or/origin_circuit_st.h"
#include "lib/subsys/subsys.h"
/** List of subscribers */
static smartlist_t *ocirc_event_rcvrs;
/** Initialize subscriber list */
static int
ocirc_event_init(void)
{
ocirc_event_rcvrs = smartlist_new();
return 0;
}
/** Free subscriber list */
static void
ocirc_event_fini(void)
{
smartlist_free(ocirc_event_rcvrs);
}
/**
* Subscribe to messages about origin circuit events
*
* Register a callback function to receive messages about origin
* circuits. The publisher calls this function synchronously.
**/
void
ocirc_event_subscribe(ocirc_event_rcvr_t fn)
{
tor_assert(fn);
/* Don't duplicate subscriptions. */
if (smartlist_contains(ocirc_event_rcvrs, fn))
return;
smartlist_add(ocirc_event_rcvrs, fn);
}
/**
* Publish a message about OR connection events
*
* This calls the subscriber receiver function synchronously.
**/
void
ocirc_event_publish(const ocirc_event_msg_t *msg)
{
SMARTLIST_FOREACH_BEGIN(ocirc_event_rcvrs, ocirc_event_rcvr_t, fn) {
tor_assert(fn);
(*fn)(msg);
} SMARTLIST_FOREACH_END(fn);
}
const subsys_fns_t sys_ocirc_event = {
.name = "ocirc_event",
.supported = true,
.level = -32,
.initialize = ocirc_event_init,
.shutdown = ocirc_event_fini,
};
+89
View File
@@ -0,0 +1,89 @@
/* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file ocirc_event.h
* \brief Header file for ocirc_event.c
**/
#ifndef TOR_OCIRC_EVENT_H
#define TOR_OCIRC_EVENT_H
#include <stdbool.h>
#include "lib/cc/torint.h"
/** Used to indicate the type of a circuit event passed to the controller.
* The various types are defined in control-spec.txt */
typedef enum circuit_status_event_t {
CIRC_EVENT_LAUNCHED = 0,
CIRC_EVENT_BUILT = 1,
CIRC_EVENT_EXTENDED = 2,
CIRC_EVENT_FAILED = 3,
CIRC_EVENT_CLOSED = 4,
} circuit_status_event_t;
/** Message for origin circuit state update */
typedef struct ocirc_state_msg_t {
uint32_t gid; /**< global ID (only origin circuits have them) */
int state; /**< new circuit state */
bool onehop; /**< one-hop circuit? */
} ocirc_state_msg_t;
/**
* Message when a channel gets associated to a circuit.
*
* This doesn't always correspond to something in circuitbuild.c
* setting the n_chan field in the circuit. For some reason, if
* circuit_handle_first_hop() launches a new circuit, it doesn't set
* the n_chan field.
*/
typedef struct ocirc_chan_msg_t {
uint32_t gid; /**< global ID */
uint64_t chan; /**< channel ID */
bool onehop; /**< one-hop circuit? */
} ocirc_chan_msg_t;
/**
* Message for origin circuit status event
*
* This contains information that ends up in CIRC control protocol events.
*/
typedef struct ocirc_cevent_msg_t {
uint32_t gid; /**< global ID */
int evtype; /**< event type */
int reason; /**< reason */
bool onehop; /**< one-hop circuit? */
} ocirc_cevent_msg_t;
/** Discriminant values for origin circuit event message */
typedef enum ocirc_msgtype_t {
OCIRC_MSGTYPE_STATE,
OCIRC_MSGTYPE_CHAN,
OCIRC_MSGTYPE_CEVENT,
} ocirc_msgtype_t;
/** Discriminated union for the actual message */
typedef struct ocirc_event_msg_t {
int type;
union {
ocirc_state_msg_t state;
ocirc_chan_msg_t chan;
ocirc_cevent_msg_t cevent;
} u;
} ocirc_event_msg_t;
/**
* Receiver function pointer for origin circuit subscribers
*
* This function gets called synchronously by the publisher.
**/
typedef void (*ocirc_event_rcvr_t)(const ocirc_event_msg_t *);
void ocirc_event_subscribe(ocirc_event_rcvr_t fn);
#ifdef OCIRC_EVENT_PRIVATE
void ocirc_event_publish(const ocirc_event_msg_t *msg);
#endif
#endif /* defined(TOR_OCIRC_EVENT_STATE_H) */
+13
View File
@@ -0,0 +1,13 @@
/* Copyright (c) 2007-2018, The Tor Project, Inc. */
/**
* \file ocirc_event_sys.h
* \brief Declare subsystem object for the origin circuit event module.
**/
#ifndef TOR_OCIRC_EVENT_SYS_H
#define TOR_OCIRC_EVENT_SYS_H
extern const struct subsys_fns_t sys_ocirc_event;
#endif /* defined(TOR_OCIRC_EVENT_H) */
+81
View File
@@ -0,0 +1,81 @@
/* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file orconn_event.c
* \brief Publish state change messages for OR connections
*
* Implements a basic publish-subscribe framework for messages about
* the state of OR connections. The publisher calls the subscriber
* callback functions synchronously.
*
* Although the synchronous calls might not simplify the call graph,
* this approach improves data isolation because the publisher doesn't
* need knowledge about the internals of subscribing subsystems. It
* also avoids race conditions that might occur in asynchronous
* frameworks.
**/
#include "core/or/or.h"
#include "lib/subsys/subsys.h"
#define ORCONN_EVENT_PRIVATE
#include "core/or/orconn_event.h"
#include "core/or/orconn_event_sys.h"
/** List of subscribers */
static smartlist_t *orconn_event_rcvrs;
/** Initialize subscriber list */
static int
orconn_event_init(void)
{
orconn_event_rcvrs = smartlist_new();
return 0;
}
/** Free subscriber list */
static void
orconn_event_fini(void)
{
smartlist_free(orconn_event_rcvrs);
}
/**
* Subscribe to messages about OR connection events
*
* Register a callback function to receive messages about ORCONNs.
* The publisher calls this function synchronously.
**/
void
orconn_event_subscribe(orconn_event_rcvr_t fn)
{
tor_assert(fn);
/* Don't duplicate subscriptions. */
if (smartlist_contains(orconn_event_rcvrs, fn))
return;
smartlist_add(orconn_event_rcvrs, fn);
}
/**
* Publish a message about OR connection events
*
* This calls the subscriber receiver function synchronously.
**/
void
orconn_event_publish(const orconn_event_msg_t *msg)
{
SMARTLIST_FOREACH_BEGIN(orconn_event_rcvrs, orconn_event_rcvr_t, fn) {
tor_assert(fn);
(*fn)(msg);
} SMARTLIST_FOREACH_END(fn);
}
const subsys_fns_t sys_orconn_event = {
.name = "orconn_event",
.supported = true,
.level = -33,
.initialize = orconn_event_init,
.shutdown = orconn_event_fini,
};
+120
View File
@@ -0,0 +1,120 @@
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file orconn_event.h
* \brief Header file for orconn_event.c
*
* The OR_CONN_STATE_* symbols are here to make it easier for
* subscribers to make decisions based on the messages that they
* receive.
**/
#ifndef TOR_ORCONN_EVENT_H
#define TOR_ORCONN_EVENT_H
/**
* @name States of OR connections
*
* These must be in a partial ordering such that usually no OR
* connection will transition from a higher-numbered state to a
* lower-numbered one. Code such as bto_update_best() depends on this
* ordering to determine the best state it's seen so far.
* @{ */
#define OR_CONN_STATE_MIN_ 1
/** State for a connection to an OR: waiting for connect() to finish. */
#define OR_CONN_STATE_CONNECTING 1
/** State for a connection to an OR: waiting for proxy handshake to complete */
#define OR_CONN_STATE_PROXY_HANDSHAKING 2
/** State for an OR connection client: SSL is handshaking, not done
* yet. */
#define OR_CONN_STATE_TLS_HANDSHAKING 3
/** State for a connection to an OR: We're doing a second SSL handshake for
* renegotiation purposes. (V2 handshake only.) */
#define OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING 4
/** State for a connection at an OR: We're waiting for the client to
* renegotiate (to indicate a v2 handshake) or send a versions cell (to
* indicate a v3 handshake) */
#define OR_CONN_STATE_TLS_SERVER_RENEGOTIATING 5
/** State for an OR connection: We're done with our SSL handshake, we've done
* renegotiation, but we haven't yet negotiated link protocol versions and
* sent a netinfo cell. */
#define OR_CONN_STATE_OR_HANDSHAKING_V2 6
/** State for an OR connection: We're done with our SSL handshake, but we
* haven't yet negotiated link protocol versions, done a V3 handshake, and
* sent a netinfo cell. */
#define OR_CONN_STATE_OR_HANDSHAKING_V3 7
/** State for an OR connection: Ready to send/receive cells. */
#define OR_CONN_STATE_OPEN 8
#define OR_CONN_STATE_MAX_ 8
/** @} */
/** Used to indicate the type of an OR connection event passed to the
* controller. The various types are defined in control-spec.txt */
typedef enum or_conn_status_event_t {
OR_CONN_EVENT_LAUNCHED = 0,
OR_CONN_EVENT_CONNECTED = 1,
OR_CONN_EVENT_FAILED = 2,
OR_CONN_EVENT_CLOSED = 3,
OR_CONN_EVENT_NEW = 4,
} or_conn_status_event_t;
/** Discriminant values for orconn event message */
typedef enum orconn_msgtype_t {
ORCONN_MSGTYPE_STATE,
ORCONN_MSGTYPE_STATUS,
} orconn_msgtype_t;
/**
* Message for orconn state update
*
* This contains information about internal state changes of
* or_connection_t objects. The chan and proxy_type fields are
* additional information that a subscriber may need to make
* decisions.
**/
typedef struct orconn_state_msg_t {
uint64_t gid; /**< connection's global ID */
uint64_t chan; /**< associated channel ID */
int proxy_type; /**< connection's proxy type */
uint8_t state; /**< new connection state */
} orconn_state_msg_t;
/**
* Message for orconn status event
*
* This contains information that ends up in ORCONN control protocol
* events.
**/
typedef struct orconn_status_msg_t {
uint64_t gid; /**< connection's global ID */
int status; /**< or_conn_status_event_t */
int reason; /**< reason */
} orconn_status_msg_t;
/** Discriminated union for the actual message */
typedef struct orconn_event_msg_t {
int type;
union {
orconn_state_msg_t state;
orconn_status_msg_t status;
} u;
} orconn_event_msg_t;
/**
* Receiver function pointer for OR subscribers
*
* This function gets called synchronously by the publisher.
**/
typedef void (*orconn_event_rcvr_t)(const orconn_event_msg_t *);
void orconn_event_subscribe(orconn_event_rcvr_t);
#ifdef ORCONN_EVENT_PRIVATE
void orconn_event_publish(const orconn_event_msg_t *);
#endif
#endif /* defined(TOR_ORCONN_EVENT_H) */
+12
View File
@@ -0,0 +1,12 @@
/* Copyright (c) 2007-2018, The Tor Project, Inc. */
/**
* \file orconn_event_sys.h
* \brief Declare subsystem object for the OR connection event module.
**/
#ifndef TOR_ORCONN_EVENT_SYS_H
#define TOR_ORCONN_EVENT_SYS_H
extern const struct subsys_fns_t sys_orconn_event;
#endif /* defined(TOR_ORCONN_SYS_H) */
+53
View File
@@ -0,0 +1,53 @@
/* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file btrack.c
* \brief Bootstrap trackers
*
* Initializes and shuts down the specific bootstrap trackers. These
* trackers help the reporting of bootstrap progress by maintaining
* state information about various subsystems within tor. When the
* correct state changes happen, these trackers emit controller
* events.
*
* These trackers avoid referring directly to the internals of state
* objects of other subsystems.
*
* btrack_circuit.c contains the tracker for origin circuits.
*
* btrack_orconn.c contains the tracker for OR connections.
*
* Eventually there will be a tracker for directory downloads as well.
**/
#include "feature/control/btrack_circuit.h"
#include "feature/control/btrack_orconn.h"
#include "feature/control/btrack_sys.h"
#include "lib/subsys/subsys.h"
static int
btrack_init(void)
{
if (btrack_orconn_init())
return -1;
if (btrack_circ_init())
return -1;
return 0;
}
static void
btrack_fini(void)
{
btrack_orconn_fini();
btrack_circ_fini();
}
const subsys_fns_t sys_btrack = {
.name = "btrack",
.supported = true,
.level = -30,
.initialize = btrack_init,
.shutdown = btrack_fini,
};
+164
View File
@@ -0,0 +1,164 @@
/* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file btrack_circuit.c
* \brief Bootstrap tracker for origin circuits
*
* Track state changes of origin circuits, as published by the circuit
* subsystem.
**/
#include "core/or/or.h"
#include "core/or/ocirc_event.h"
#include "feature/control/btrack_circuit.h"
#include "feature/control/control.h"
#include "lib/log/log.h"
/** Pair of a best origin circuit GID with its state or status */
typedef struct btc_best_t {
uint32_t gid;
int val;
} btc_best_t;
/** GID and state of the best origin circuit we've seen so far */
static btc_best_t best_any_state = { 0, -1 };
/** GID and state of the best application circuit we've seen so far */
static btc_best_t best_ap_state = { 0, -1 };
/** GID and status of the best origin circuit we've seen so far */
static btc_best_t best_any_evtype = { 0, -1 };
/** GID and status of the best application circuit we've seen so far */
static btc_best_t best_ap_evtype = { 0, -1 };
/** Reset cached "best" values */
static void
btc_reset_bests(void)
{
best_any_state.gid = best_ap_state.gid = 0;
best_any_state.val = best_ap_state.val = -1;
best_any_evtype.gid = best_ap_state.gid = 0;
best_any_evtype.val = best_ap_evtype.val = -1;
}
/** True if @a state is a "better" origin circuit state than @a best->val */
static bool
btc_state_better(int state, const btc_best_t *best)
{
return state > best->val;
}
/**
* Definine an ordering on circuit status events
*
* The CIRC_EVENT_ constants aren't sorted in a useful order, so this
* array helps to decode them. This approach depends on the statuses
* being nonnegative and dense.
**/
static int circ_event_order[] = {
[CIRC_EVENT_FAILED] = -1,
[CIRC_EVENT_CLOSED] = -1,
[CIRC_EVENT_LAUNCHED] = 1,
[CIRC_EVENT_EXTENDED] = 2,
[CIRC_EVENT_BUILT] = 3,
};
#define N_CIRC_EVENT_ORDER \
(sizeof(circ_event_order) / sizeof(circ_event_order[0]))
/** True if @a state is a "better" origin circuit event status than @a
best->val */
static bool
btc_evtype_better(int state, const btc_best_t *best)
{
if (state < 0)
return false;
if (best->val < 0)
return true;
tor_assert(state >= 0 && (unsigned)state < N_CIRC_EVENT_ORDER);
tor_assert(best->val >= 0 && (unsigned)best->val < N_CIRC_EVENT_ORDER);
return circ_event_order[state] > circ_event_order[best->val];
}
static bool
btc_update_state(const ocirc_state_msg_t *msg, btc_best_t *best,
const char *type)
{
if (btc_state_better(msg->state, best)) {
log_info(LD_BTRACK, "CIRC BEST_%s state %d->%d gid=%"PRIu32, type,
best->val, msg->state, msg->gid);
best->gid = msg->gid;
best->val = msg->state;
return true;
}
return false;
}
static bool
btc_update_evtype(const ocirc_cevent_msg_t *msg, btc_best_t *best,
const char *type)
{
if (btc_evtype_better(msg->evtype, best)) {
log_info(LD_BTRACK, "CIRC BEST_%s evtype %d->%d gid=%"PRIu32, type,
best->val, msg->evtype, msg->gid);
best->gid = msg->gid;
best->val = msg->evtype;
return true;
}
return false;
}
static void
btc_state_rcvr(const ocirc_state_msg_t *msg)
{
log_debug(LD_BTRACK, "CIRC gid=%"PRIu32" state=%d onehop=%d",
msg->gid, msg->state, msg->onehop);
btc_update_state(msg, &best_any_state, "ANY");
if (msg->onehop)
return;
btc_update_state(msg, &best_ap_state, "AP");
}
static void
btc_cevent_rcvr(const ocirc_cevent_msg_t *msg)
{
log_debug(LD_BTRACK, "CIRC gid=%"PRIu32" evtype=%d reason=%d onehop=%d",
msg->gid, msg->evtype, msg->reason, msg->onehop);
btc_update_evtype(msg, &best_any_evtype, "ANY");
if (msg->onehop)
return;
btc_update_evtype(msg, &best_ap_evtype, "AP");
}
static void
btc_event_rcvr(const ocirc_event_msg_t *msg)
{
switch (msg->type) {
case OCIRC_MSGTYPE_STATE:
return btc_state_rcvr(&msg->u.state);
case OCIRC_MSGTYPE_CHAN:
log_debug(LD_BTRACK, "CIRC gid=%"PRIu32" chan=%"PRIu64" onehop=%d",
msg->u.chan.gid, msg->u.chan.chan, msg->u.chan.onehop);
break;
case OCIRC_MSGTYPE_CEVENT:
return btc_cevent_rcvr(&msg->u.cevent);
default:
break;
}
}
int
btrack_circ_init(void)
{
ocirc_event_subscribe(btc_event_rcvr);
return 0;
}
void
btrack_circ_fini(void)
{
btc_reset_bests();
}
+15
View File
@@ -0,0 +1,15 @@
/* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file btrack_circuit.h
* \brief Header file for btrack_circuit.c
**/
#ifndef TOR_BTRACK_CIRCUIT_H
#define TOR_BTRACK_CIRCUIT_H
int btrack_circ_init(void);
void btrack_circ_fini(void);
#endif /* defined(TOR_BTRACK_CIRCUIT_H) */
+206
View File
@@ -0,0 +1,206 @@
/* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file btrack_orconn.c
* \brief Bootstrap tracker for OR connections
*
* Track state changes of OR connections, as published by the
* connection subsystem. Also track circuit launch events, because
* they're one of the few ways to discover the association between a
* channel (and OR connection) and a circuit.
*
* We track all OR connections that we receive events for, whether or
* not they're carrying origin circuits. (An OR connection might
* carry origin circuits only after we first find out about that
* connection.)
*
* All origin ORCONN events update the "any" state variables, while
* only application ORCONN events update the "ap" state variables (and
* also update the "any") variables.
*
* We do this because we want to report the first increments of
* connection progress as the earliest bootstrap phases. This results
* in a better user experience because failures here translate into
* zero or very small amounts of displayed progress, instead of
* progress stuck near completion. The first connection to a relay
* might be a one-hop circuit for directory lookups, or it might be a
* connection for an application circuit because we already have
* enough directory info to build an application circuit.
*
* We call functions in btrack_orconn_cevent.c to generate the actual
* controller events, because some of the state decoding we need to do
* is complicated.
**/
#include <stdbool.h>
#include "core/or/or.h"
#define BTRACK_ORCONN_PRIVATE
#include "core/or/ocirc_event.h"
#include "core/or/orconn_event.h"
#include "feature/control/btrack_orconn.h"
#include "feature/control/btrack_orconn_cevent.h"
#include "feature/control/btrack_orconn_maps.h"
#include "lib/log/log.h"
/** Pair of a best ORCONN GID and with its state */
typedef struct bto_best_t {
uint64_t gid;
int state;
} bto_best_t;
/** GID and state of the best ORCONN we've seen so far */
static bto_best_t best_any = { 0, -1 };
/** GID and state of the best application circuit ORCONN we've seen so far */
static bto_best_t best_ap = { 0, -1 };
/**
* Update a cached state of a best ORCONN progress we've seen so far.
*
* Return true if the new state is better than the old.
**/
static bool
bto_update_best(const bt_orconn_t *bto, bto_best_t *best, const char *type)
{
if (bto->state < best->state)
return false;
/* Update even if we won't change best->state, because it's more
* recent information that a particular connection transitioned to
* that state. */
best->gid = bto->gid;
if (bto->state > best->state) {
log_info(LD_BTRACK, "ORCONN BEST_%s state %d->%d gid=%"PRIu64, type,
best->state, bto->state, bto->gid);
best->state = bto->state;
return true;
}
return false;
}
/**
* Update cached states of best ORCONN progress we've seen
*
* Only update the application ORCONN state if we know it's carrying
* an application circuit.
**/
static void
bto_update_bests(const bt_orconn_t *bto)
{
tor_assert(bto->is_orig);
if (bto_update_best(bto, &best_any, "ANY"))
bto_cevent_anyconn(bto);
if (!bto->is_onehop && bto_update_best(bto, &best_ap, "AP"))
bto_cevent_apconn(bto);
}
/** Reset cached "best" values */
static void
bto_reset_bests(void)
{
best_any.gid = best_ap.gid = 0;
best_any.state = best_ap.state = -1;
}
/**
* Update cached states of ORCONNs from the incoming message. This
* message comes from code in connection_or.c.
**/
static void
bto_state_rcvr(const orconn_state_msg_t *msg)
{
bt_orconn_t *bto;
bto = bto_find_or_new(msg->gid, msg->chan);
log_debug(LD_BTRACK, "ORCONN gid=%"PRIu64" chan=%"PRIu64
" proxy_type=%d state=%d",
msg->gid, msg->chan, msg->proxy_type, msg->state);
bto->proxy_type = msg->proxy_type;
bto->state = msg->state;
if (bto->is_orig)
bto_update_bests(bto);
}
/**
* Delete a cached ORCONN state if we get an incoming message saying
* the ORCONN is failed or closed. This message comes from code in
* control.c.
**/
static void
bto_status_rcvr(const orconn_status_msg_t *msg)
{
switch (msg->status) {
case OR_CONN_EVENT_FAILED:
case OR_CONN_EVENT_CLOSED:
log_info(LD_BTRACK, "ORCONN DELETE gid=%"PRIu64" status=%d reason=%d",
msg->gid, msg->status, msg->reason);
return bto_delete(msg->gid);
default:
break;
}
}
/** Dispatch to individual ORCONN message handlers */
static void
bto_event_rcvr(const orconn_event_msg_t *msg)
{
switch (msg->type) {
case ORCONN_MSGTYPE_STATE:
return bto_state_rcvr(&msg->u.state);
case ORCONN_MSGTYPE_STATUS:
return bto_status_rcvr(&msg->u.status);
default:
tor_assert(false);
}
}
/**
* Create or update a cached ORCONN state for a newly launched
* connection, including whether it's launched by an origin circuit
* and whether it's a one-hop circuit.
**/
static void
bto_chan_rcvr(const ocirc_event_msg_t *msg)
{
bt_orconn_t *bto;
/* Ignore other kinds of origin circuit events; we don't need them */
if (msg->type != OCIRC_MSGTYPE_CHAN)
return;
bto = bto_find_or_new(0, msg->u.chan.chan);
if (!bto->is_orig || (bto->is_onehop && !msg->u.chan.onehop)) {
log_debug(LD_BTRACK, "ORCONN LAUNCH chan=%"PRIu64" onehop=%d",
msg->u.chan.chan, msg->u.chan.onehop);
}
bto->is_orig = true;
if (!msg->u.chan.onehop)
bto->is_onehop = false;
bto_update_bests(bto);
}
/**
* Initialize the hash maps and subscribe to ORCONN and origin
* circuit events.
**/
int
btrack_orconn_init(void)
{
bto_init_maps();
orconn_event_subscribe(bto_event_rcvr);
ocirc_event_subscribe(bto_chan_rcvr);
return 0;
}
/** Clear the hash maps and reset the "best" states */
void
btrack_orconn_fini(void)
{
bto_clear_maps();
bto_reset_bests();
bto_cevent_reset();
}
+38
View File
@@ -0,0 +1,38 @@
/* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file btrack_orconn.h
* \brief Header file for btrack_orconn.c
**/
#ifndef TOR_BTRACK_ORCONN_H
#define TOR_BTRACK_ORCONN_H
#ifdef BTRACK_ORCONN_PRIVATE
#include "ht.h"
/**
* Structure for tracking OR connection states
*
* This gets linked into two hash maps: one with connection IDs, and
* another with channel IDs.
**/
typedef struct bt_orconn_t {
HT_ENTRY(bt_orconn_t) node; /**< Hash map entry indexed by gid */
HT_ENTRY(bt_orconn_t) chan_node; /**< Hash map entry indexed by channel ID */
uint64_t gid; /**< Global ID of this ORCONN */
uint64_t chan; /**< Channel ID, if known */
int proxy_type; /**< Proxy type */
uint8_t state; /**< State of this ORCONN */
bool is_orig; /**< Does this carry an origin circuit? */
bool is_onehop; /**< Is this for a one-hop circuit? */
} bt_orconn_t;
#endif /* defined(BTRACK_ORCONN_PRIVATE) */
int btrack_orconn_init(void);
void btrack_orconn_fini(void);
#endif /* defined(TOR_BTRACK_ORCONN_H) */
+159
View File
@@ -0,0 +1,159 @@
/* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file btrack_orconn_cevent.c
* \brief Emit bootstrap status events for OR connections
*
* We do some decoding of the raw OR_CONN_STATE_* values. For
* example, OR_CONN_STATE_CONNECTING means the first TCP connect()
* completing, regardless of whether it's directly to a relay instead
* of a proxy or a PT.
**/
#include <stdbool.h>
#include "core/or/or.h"
#define BTRACK_ORCONN_PRIVATE
#include "core/or/orconn_event.h"
#include "feature/control/btrack_orconn.h"
#include "feature/control/btrack_orconn_cevent.h"
#include "feature/control/control.h"
/**
* Have we completed our first OR connection?
*
* Block display of application circuit progress until we do, to avoid
* some misleading behavior of jumping to high progress.
**/
static bool bto_first_orconn = false;
/** Is the ORCONN using a pluggable transport? */
static bool
using_pt(const bt_orconn_t *bto)
{
return bto->proxy_type == PROXY_PLUGGABLE;
}
/** Is the ORCONN using a non-PT proxy? */
static bool
using_proxy(const bt_orconn_t *bto)
{
switch (bto->proxy_type) {
case PROXY_CONNECT:
case PROXY_SOCKS4:
case PROXY_SOCKS5:
return true;
default:
return false;
}
}
/**
* Emit control events when we have updated our idea of the best state
* that any OR connection has reached.
*
* Do some decoding of the ORCONN states depending on whether a PT or
* a proxy is in use.
**/
void
bto_cevent_anyconn(const bt_orconn_t *bto)
{
switch (bto->state) {
case OR_CONN_STATE_CONNECTING:
/* Exactly what kind of thing we're connecting to isn't
* information we directly get from the states in connection_or.c,
* so decode it here. */
if (using_pt(bto))
control_event_bootstrap(BOOTSTRAP_STATUS_CONN_PT, 0);
else if (using_proxy(bto))
control_event_bootstrap(BOOTSTRAP_STATUS_CONN_PROXY, 0);
else
control_event_bootstrap(BOOTSTRAP_STATUS_CONN, 0);
break;
case OR_CONN_STATE_PROXY_HANDSHAKING:
/* Similarly, starting a proxy handshake means the TCP connect()
* succeeded to the proxy. Let's be specific about what kind of
* proxy. */
if (using_pt(bto))
control_event_bootstrap(BOOTSTRAP_STATUS_CONN_DONE_PT, 0);
else if (using_proxy(bto))
control_event_bootstrap(BOOTSTRAP_STATUS_CONN_DONE_PROXY, 0);
break;
case OR_CONN_STATE_TLS_HANDSHAKING:
control_event_bootstrap(BOOTSTRAP_STATUS_CONN_DONE, 0);
break;
case OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING:
case OR_CONN_STATE_OR_HANDSHAKING_V2:
case OR_CONN_STATE_OR_HANDSHAKING_V3:
control_event_bootstrap(BOOTSTRAP_STATUS_HANDSHAKE, 0);
break;
case OR_CONN_STATE_OPEN:
control_event_bootstrap(BOOTSTRAP_STATUS_HANDSHAKE_DONE, 0);
/* Unblock directory progress display */
control_event_boot_first_orconn();
/* Unblock apconn progress display */
bto_first_orconn = true;
break;
default:
break;
}
}
/**
* Emit control events when we have updated our idea of the best state
* that any application circuit OR connection has reached.
*
* Do some decoding of the ORCONN states depending on whether a PT or
* a proxy is in use.
**/
void
bto_cevent_apconn(const bt_orconn_t *bto)
{
if (!bto_first_orconn)
return;
switch (bto->state) {
case OR_CONN_STATE_CONNECTING:
/* Exactly what kind of thing we're connecting to isn't
* information we directly get from the states in connection_or.c,
* so decode it here. */
if (using_pt(bto))
control_event_bootstrap(BOOTSTRAP_STATUS_AP_CONN_PT, 0);
else if (using_proxy(bto))
control_event_bootstrap(BOOTSTRAP_STATUS_AP_CONN_PROXY, 0);
else
control_event_bootstrap(BOOTSTRAP_STATUS_AP_CONN, 0);
break;
case OR_CONN_STATE_PROXY_HANDSHAKING:
/* Similarly, starting a proxy handshake means the TCP connect()
* succeeded to the proxy. Let's be specific about what kind of
* proxy. */
if (using_pt(bto))
control_event_bootstrap(BOOTSTRAP_STATUS_AP_CONN_DONE_PT, 0);
else if (using_proxy(bto))
control_event_bootstrap(BOOTSTRAP_STATUS_AP_CONN_DONE_PROXY, 0);
break;
case OR_CONN_STATE_TLS_HANDSHAKING:
control_event_bootstrap(BOOTSTRAP_STATUS_AP_CONN_DONE, 0);
break;
case OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING:
case OR_CONN_STATE_OR_HANDSHAKING_V2:
case OR_CONN_STATE_OR_HANDSHAKING_V3:
control_event_bootstrap(BOOTSTRAP_STATUS_AP_HANDSHAKE, 0);
break;
case OR_CONN_STATE_OPEN:
control_event_bootstrap(BOOTSTRAP_STATUS_AP_HANDSHAKE_DONE, 0);
default:
break;
}
}
/** Forget that we completed our first OR connection */
void
bto_cevent_reset(void)
{
bto_first_orconn = false;
}
@@ -0,0 +1,17 @@
/* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file btrack_orconn_cevent.h
* \brief Header file for btrack_orconn_cevent.c
**/
#ifndef TOR_BTRACK_ORCONN_CEVENT_H
#include "feature/control/btrack_orconn.h"
void bto_cevent_anyconn(const bt_orconn_t *);
void bto_cevent_apconn(const bt_orconn_t *);
void bto_cevent_reset(void);
#endif /* defined(TOR_BTRACK_ORCONN_CEVENT_H) */
+223
View File
@@ -0,0 +1,223 @@
/* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file btrack_orconn_maps.c
* \brief Hash map implementation for btrack_orconn.c
*
* These functions manipulate the hash maps that contain bt_orconn
* objects.
**/
#include <stdbool.h>
#include "core/or/or.h"
#include "ht.h"
#include "siphash.h"
#define BTRACK_ORCONN_PRIVATE
#include "feature/control/btrack_orconn.h"
#include "feature/control/btrack_orconn_maps.h"
#include "lib/log/log.h"
static inline unsigned int
bto_gid_hash_(bt_orconn_t *elm)
{
return (unsigned)siphash24g(&elm->gid, sizeof(elm->gid));
}
static inline int
bto_gid_eq_(bt_orconn_t *a, bt_orconn_t *b)
{
return a->gid == b->gid;
}
static inline unsigned int
bto_chan_hash_(bt_orconn_t *elm)
{
return (unsigned)siphash24g(&elm->chan, sizeof(elm->chan));
}
static inline int
bto_chan_eq_(bt_orconn_t *a, bt_orconn_t *b)
{
return a->chan == b->chan;
}
HT_HEAD(bto_gid_ht, bt_orconn_t);
HT_PROTOTYPE(bto_gid_ht, bt_orconn_t, node, bto_gid_hash_, bto_gid_eq_)
HT_GENERATE2(bto_gid_ht, bt_orconn_t, node,
bto_gid_hash_, bto_gid_eq_, 0.6,
tor_reallocarray_, tor_free_)
static struct bto_gid_ht *bto_gid_map;
HT_HEAD(bto_chan_ht, bt_orconn_t);
HT_PROTOTYPE(bto_chan_ht, bt_orconn_t, chan_node, bto_chan_hash_, bto_chan_eq_)
HT_GENERATE2(bto_chan_ht, bt_orconn_t, chan_node,
bto_chan_hash_, bto_chan_eq_, 0.6,
tor_reallocarray_, tor_free_)
static struct bto_chan_ht *bto_chan_map;
/** Clear the GID hash map, freeing any bt_orconn_t objects that become
* unreferenced */
static void
bto_gid_clear_map(void)
{
bt_orconn_t **elt, **next, *c;
for (elt = HT_START(bto_gid_ht, bto_gid_map);
elt;
elt = next) {
c = *elt;
next = HT_NEXT_RMV(bto_gid_ht, bto_gid_map, elt);
c->gid = 0;
/* Don't delete if chan ID isn't zero: it's still in the chan hash map */
if (!c->chan)
tor_free(c);
}
HT_CLEAR(bto_gid_ht, bto_gid_map);
tor_free(bto_gid_map);
}
/** Clear the chan ID hash map, freeing any bt_orconn_t objects that
* become unreferenced */
static void
bto_chan_clear_map(void)
{
bt_orconn_t **elt, **next, *c;
for (elt = HT_START(bto_chan_ht, bto_chan_map);
elt;
elt = next) {
c = *elt;
next = HT_NEXT_RMV(bto_chan_ht, bto_chan_map, elt);
c->chan = 0;
/* Don't delete if GID isn't zero, it's still in the GID hash map */
if (!c->gid)
tor_free(c);
}
HT_CLEAR(bto_chan_ht, bto_chan_map);
tor_free(bto_chan_map);
}
/** Delete a bt_orconn from the hash maps by GID */
void
bto_delete(uint64_t gid)
{
bt_orconn_t key, *bto;
key.gid = gid;
key.chan = 0;
bto = HT_FIND(bto_gid_ht, bto_gid_map, &key);
if (!bto) {
/* The orconn might be unregistered because it's an EXT_OR_CONN? */
log_debug(LD_BTRACK, "tried to delete unregistered ORCONN gid=%"PRIu64,
gid);
return;
}
HT_REMOVE(bto_gid_ht, bto_gid_map, &key);
if (bto->chan) {
key.chan = bto->chan;
HT_REMOVE(bto_chan_ht, bto_chan_map, &key);
}
tor_free(bto);
}
/**
* Helper for bto_find_or_new().
*
* Update GID and chan ID of an existing bt_orconn object if needed,
* given a search key previously used within bto_find_or_new().
**/
static bt_orconn_t *
bto_update(bt_orconn_t *bto, const bt_orconn_t *key)
{
/* ORCONN GIDs shouldn't change once assigned */
tor_assert(!bto->gid || !key->gid || bto->gid == key->gid);
if (!bto->gid && key->gid) {
/* Got a gid when we didn't already have one; insert into gid map */
log_debug(LD_BTRACK, "ORCONN chan=%"PRIu64" newgid=%"PRIu64, key->chan,
key->gid);
bto->gid = key->gid;
HT_INSERT(bto_gid_ht, bto_gid_map, bto);
}
/* association of ORCONN with channel shouldn't change */
tor_assert(!bto->chan || !key->chan || bto->chan == key->chan);
if (!bto->chan && key->chan) {
/* Got a chan when we didn't already have one; insert into chan map */
log_debug(LD_BTRACK, "ORCONN gid=%"PRIu64" newchan=%"PRIu64,
bto->gid, key->chan);
bto->chan = key->chan;
HT_INSERT(bto_chan_ht, bto_chan_map, bto);
}
return bto;
}
/** Helper for bto_find_or_new() */
static bt_orconn_t *
bto_new(const bt_orconn_t *key)
{
struct bt_orconn_t *bto = tor_malloc(sizeof(*bto));
bto->gid = key->gid;
bto->chan = key->chan;
bto->state = 0;
bto->proxy_type = 0;
bto->is_orig = false;
bto->is_onehop = true;
if (bto->gid)
HT_INSERT(bto_gid_ht, bto_gid_map, bto);
if (bto->chan)
HT_INSERT(bto_chan_ht, bto_chan_map, bto);
return bto;
}
/**
* Insert a new bt_orconn with the given GID and chan ID, or update
* the GID and chan ID if one already exists.
*
* Return the found or allocated bt_orconn.
**/
bt_orconn_t *
bto_find_or_new(uint64_t gid, uint64_t chan)
{
bt_orconn_t key, *bto = NULL;
tor_assert(gid || chan);
key.gid = gid;
key.chan = chan;
if (key.gid)
bto = HT_FIND(bto_gid_ht, bto_gid_map, &key);
if (!bto && key.chan) {
/* Not found by GID; look up by chan ID */
bto = HT_FIND(bto_chan_ht, bto_chan_map, &key);
}
if (bto)
return bto_update(bto, &key);
else
return bto_new(&key);
}
/** Initialize the hash maps */
void
bto_init_maps(void)
{
bto_gid_map = tor_malloc(sizeof(*bto_gid_map));
HT_INIT(bto_gid_ht, bto_gid_map);
bto_chan_map = tor_malloc(sizeof(*bto_chan_map));
HT_INIT(bto_chan_ht, bto_chan_map);
}
/** Clear the hash maps, freeing all associated storage */
void
bto_clear_maps(void)
{
bto_gid_clear_map();
bto_chan_clear_map();
}
+17
View File
@@ -0,0 +1,17 @@
/* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file btrack_orconn_maps.h
* \brief Header file for btrack_orconn_maps.c
**/
#ifndef TOR_BTRACK_ORCONN_MAPS_H
void bto_delete(uint64_t);
bt_orconn_t *bto_find_or_new(uint64_t, uint64_t);
void bto_init_maps(void);
void bto_clear_maps(void);
#endif /* defined(TOR_BTRACK_ORCONN_MAPS_H) */
+14
View File
@@ -0,0 +1,14 @@
/* Copyright (c) 2007-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
* \file btrack_sys.h
* \brief Declare subsystem object for the bootstrap tracker susbystem.
**/
#ifndef TOR_BTRACK_SYS_H
#define TOR_BTRACK_SYS_H
extern const struct subsys_fns_t sys_btrack;
#endif /* defined(TOR_BTRACK_SYS_H) */
+4 -1
View File
@@ -34,6 +34,7 @@
**/
#define CONTROL_PRIVATE
#define OCIRC_EVENT_PRIVATE
#include "core/or/or.h"
#include "app/config/config.h"
@@ -50,6 +51,7 @@
#include "core/or/command.h"
#include "core/or/connection_edge.h"
#include "core/or/connection_or.h"
#include "core/or/ocirc_event.h"
#include "core/or/policies.h"
#include "core/or/reasons.h"
#include "core/or/versions.h"
@@ -3749,7 +3751,7 @@ handle_control_extendcircuit(control_connection_t *conn, uint32_t len,
connection_printf_to_buf(conn, "250 EXTENDED %lu\r\n",
(unsigned long)circ->global_identifier);
if (zero_circ) /* send a 'launched' event, for completeness */
control_event_circuit_status(circ, CIRC_EVENT_LAUNCHED, 0);
circuit_event_status(circ, CIRC_EVENT_LAUNCHED, 0);
done:
SMARTLIST_FOREACH(router_nicknames, char *, n, tor_free(n));
smartlist_free(router_nicknames);
@@ -5625,6 +5627,7 @@ control_event_circuit_status(origin_circuit_t *circ, circuit_status_event_t tp,
{
const char *status;
char reasons[64] = "";
if (!EVENT_IS_INTERESTING(EVENT_CIRCUIT_STATUS))
return 0;
tor_assert(circ);
+36 -28
View File
@@ -12,15 +12,7 @@
#ifndef TOR_CONTROL_H
#define TOR_CONTROL_H
/** Used to indicate the type of a circuit event passed to the controller.
* The various types are defined in control-spec.txt */
typedef enum circuit_status_event_t {
CIRC_EVENT_LAUNCHED = 0,
CIRC_EVENT_BUILT = 1,
CIRC_EVENT_EXTENDED = 2,
CIRC_EVENT_FAILED = 3,
CIRC_EVENT_CLOSED = 4,
} circuit_status_event_t;
#include "core/or/ocirc_event.h"
/** Used to indicate the type of a CIRC_MINOR event passed to the controller.
* The various types are defined in control-spec.txt . */
@@ -29,6 +21,8 @@ typedef enum circuit_status_minor_event_t {
CIRC_MINOR_EVENT_CANNIBALIZED,
} circuit_status_minor_event_t;
#include "core/or/orconn_event.h"
/** Used to indicate the type of a stream event passed to the controller.
* The various types are defined in control-spec.txt */
typedef enum stream_status_event_t {
@@ -43,16 +37,6 @@ typedef enum stream_status_event_t {
STREAM_EVENT_REMAP = 8
} stream_status_event_t;
/** Used to indicate the type of an OR connection event passed to the
* controller. The various types are defined in control-spec.txt */
typedef enum or_conn_status_event_t {
OR_CONN_EVENT_LAUNCHED = 0,
OR_CONN_EVENT_CONNECTED = 1,
OR_CONN_EVENT_FAILED = 2,
OR_CONN_EVENT_CLOSED = 3,
OR_CONN_EVENT_NEW = 4,
} or_conn_status_event_t;
/** Used to indicate the type of a buildtime event */
typedef enum buildtimeout_set_event_t {
BUILDTIMEOUT_SET_EVENT_COMPUTED = 0,
@@ -67,18 +51,42 @@ typedef enum buildtimeout_set_event_t {
typedef enum {
BOOTSTRAP_STATUS_UNDEF=-1,
BOOTSTRAP_STATUS_STARTING=0,
BOOTSTRAP_STATUS_CONN_DIR=5,
BOOTSTRAP_STATUS_HANDSHAKE=-2,
BOOTSTRAP_STATUS_HANDSHAKE_DIR=10,
BOOTSTRAP_STATUS_ONEHOP_CREATE=15,
BOOTSTRAP_STATUS_REQUESTING_STATUS=20,
BOOTSTRAP_STATUS_LOADING_STATUS=25,
/* Initial connection to any relay */
BOOTSTRAP_STATUS_CONN_PT=1,
BOOTSTRAP_STATUS_CONN_DONE_PT=2,
BOOTSTRAP_STATUS_CONN_PROXY=3,
BOOTSTRAP_STATUS_CONN_DONE_PROXY=4,
BOOTSTRAP_STATUS_CONN=5,
BOOTSTRAP_STATUS_CONN_DONE=10,
BOOTSTRAP_STATUS_HANDSHAKE=14,
BOOTSTRAP_STATUS_HANDSHAKE_DONE=15,
/* Loading directory info */
BOOTSTRAP_STATUS_ONEHOP_CREATE=20,
BOOTSTRAP_STATUS_REQUESTING_STATUS=25,
BOOTSTRAP_STATUS_LOADING_STATUS=30,
BOOTSTRAP_STATUS_LOADING_KEYS=40,
BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS=45,
BOOTSTRAP_STATUS_LOADING_DESCRIPTORS=50,
BOOTSTRAP_STATUS_CONN_OR=80,
BOOTSTRAP_STATUS_HANDSHAKE_OR=85,
BOOTSTRAP_STATUS_CIRCUIT_CREATE=90,
BOOTSTRAP_STATUS_ENOUGH_DIRINFO=75,
/* Connecting to a relay for AP circuits */
BOOTSTRAP_STATUS_AP_CONN_PT=76,
BOOTSTRAP_STATUS_AP_CONN_DONE_PT=77,
BOOTSTRAP_STATUS_AP_CONN_PROXY=78,
BOOTSTRAP_STATUS_AP_CONN_DONE_PROXY=79,
BOOTSTRAP_STATUS_AP_CONN=80,
BOOTSTRAP_STATUS_AP_CONN_DONE=85,
BOOTSTRAP_STATUS_AP_HANDSHAKE=89,
BOOTSTRAP_STATUS_AP_HANDSHAKE_DONE=90,
/* Creating AP circuits */
BOOTSTRAP_STATUS_CIRCUIT_CREATE=95,
BOOTSTRAP_STATUS_DONE=100
} bootstrap_status_t;
+42 -17
View File
@@ -33,10 +33,24 @@ static const struct {
} boot_to_str_tab[] = {
{ BOOTSTRAP_STATUS_UNDEF, "undef", "Undefined" },
{ BOOTSTRAP_STATUS_STARTING, "starting", "Starting" },
{ BOOTSTRAP_STATUS_CONN_DIR, "conn_dir", "Connecting to directory server" },
{ BOOTSTRAP_STATUS_HANDSHAKE, "status_handshake", "Finishing handshake" },
{ BOOTSTRAP_STATUS_HANDSHAKE_DIR, "handshake_dir",
"Finishing handshake with directory server" },
/* Initial connection to any relay */
{ BOOTSTRAP_STATUS_CONN_PT, "conn_pt", "Connecting to pluggable transport" },
{ BOOTSTRAP_STATUS_CONN_DONE_PT, "conn_done_pt",
"Connected to pluggable transport" },
{ BOOTSTRAP_STATUS_CONN_PROXY, "conn_proxy", "Connecting to proxy" },
{ BOOTSTRAP_STATUS_CONN_DONE_PROXY, "conn_done_proxy",
"Connected to proxy" },
{ BOOTSTRAP_STATUS_CONN, "conn", "Connecting to a relay" },
{ BOOTSTRAP_STATUS_CONN_DONE, "conn_done", "Connected to a relay" },
{ BOOTSTRAP_STATUS_HANDSHAKE, "handshake",
"Handshaking with a relay" },
{ BOOTSTRAP_STATUS_HANDSHAKE_DONE, "handshake_done",
"Handshake with a relay done" },
/* Loading directory info */
{ BOOTSTRAP_STATUS_ONEHOP_CREATE, "onehop_create",
"Establishing an encrypted directory connection" },
{ BOOTSTRAP_STATUS_REQUESTING_STATUS, "requesting_status",
@@ -49,9 +63,30 @@ static const struct {
"Asking for relay descriptors" },
{ BOOTSTRAP_STATUS_LOADING_DESCRIPTORS, "loading_descriptors",
"Loading relay descriptors" },
{ BOOTSTRAP_STATUS_CONN_OR, "conn_or", "Connecting to the Tor network" },
{ BOOTSTRAP_STATUS_HANDSHAKE_OR, "handshake_or",
"Finishing handshake with first hop" },
{ BOOTSTRAP_STATUS_ENOUGH_DIRINFO, "enough_dirinfo",
"Loaded enough directory info to build circuits" },
/* Connecting to a relay for AP circuits */
{ BOOTSTRAP_STATUS_AP_CONN_PT, "ap_conn_pt",
"Connecting to pluggable transport to build circuits" },
{ BOOTSTRAP_STATUS_AP_CONN_DONE_PT, "ap_conn_done_pt",
"Connected to pluggable transport to build circuits" },
{ BOOTSTRAP_STATUS_AP_CONN_PROXY, "ap_conn_proxy",
"Connecting to proxy " },
{ BOOTSTRAP_STATUS_AP_CONN_DONE_PROXY, "ap_conn_done_proxy",
"Connected to proxy to build circuits" },
{ BOOTSTRAP_STATUS_AP_CONN, "ap_conn",
"Connecting to a relay to build circuits" },
{ BOOTSTRAP_STATUS_AP_CONN_DONE, "ap_conn_done",
"Connected to a relay to build circuits" },
{ BOOTSTRAP_STATUS_AP_HANDSHAKE, "ap_handshake",
"Finishing handshake with a relay to build circuits" },
{ BOOTSTRAP_STATUS_AP_HANDSHAKE_DONE, "ap_handshake_done",
"Handshake fininshed with a relay to build circuits" },
/* Creating AP circuits */
{ BOOTSTRAP_STATUS_CIRCUIT_CREATE, "circuit_create",
"Establishing a Tor circuit" },
{ BOOTSTRAP_STATUS_DONE, "done", "Done" },
@@ -151,16 +186,6 @@ control_event_bootstrap(bootstrap_status_t status, int progress)
if (bootstrap_percent == BOOTSTRAP_STATUS_DONE)
return; /* already bootstrapped; nothing to be done here. */
/* special case for handshaking status, since our TLS handshaking code
* can't distinguish what the connection is going to be for. */
if (status == BOOTSTRAP_STATUS_HANDSHAKE) {
if (bootstrap_percent < BOOTSTRAP_STATUS_CONN_OR) {
status = BOOTSTRAP_STATUS_HANDSHAKE_DIR;
} else {
status = BOOTSTRAP_STATUS_HANDSHAKE_OR;
}
}
if (status <= bootstrap_percent) {
/* If there's no new progress, return early. */
if (!progress || progress <= bootstrap_percent)
+2 -2
View File
@@ -2546,7 +2546,7 @@ count_loading_descriptors_progress(void)
if (fraction > 1.0)
return 0; /* it's not the number of descriptors holding us back */
return BOOTSTRAP_STATUS_LOADING_DESCRIPTORS + (int)
(fraction*(BOOTSTRAP_STATUS_CONN_OR-1 -
(fraction*(BOOTSTRAP_STATUS_ENOUGH_DIRINFO-1 -
BOOTSTRAP_STATUS_LOADING_DESCRIPTORS));
}
@@ -2633,7 +2633,7 @@ update_router_have_minimum_dir_info(void)
/* If paths have just become available in this update. */
if (res && !have_min_dir_info) {
control_event_client_status(LOG_NOTICE, "ENOUGH_DIR_INFO");
control_event_boot_dir(BOOTSTRAP_STATUS_CONN_OR, 0);
control_event_boot_dir(BOOTSTRAP_STATUS_ENOUGH_DIRINFO, 0);
log_info(LD_DIR,
"We now have enough directory information to build circuits.");
}
+1 -1
View File
@@ -90,7 +90,7 @@ connection_ext_or_transition(or_connection_t *conn)
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_or_event_status(conn, OR_CONN_EVENT_NEW, 0);
connection_tls_start_handshake(conn, 1);
}
+1 -1
View File
@@ -1268,7 +1268,7 @@ static const char *domain_list[] = {
"GENERAL", "CRYPTO", "NET", "CONFIG", "FS", "PROTOCOL", "MM",
"HTTP", "APP", "CONTROL", "CIRC", "REND", "BUG", "DIR", "DIRSERV",
"OR", "EDGE", "ACCT", "HIST", "HANDSHAKE", "HEARTBEAT", "CHANNEL",
"SCHED", "GUARD", "CONSDIFF", "DOS", "PROCESS", "PT", NULL
"SCHED", "GUARD", "CONSDIFF", "DOS", "PROCESS", "PT", "BTRACK", NULL
};
/** Return a bitmask for the log domain for which <b>domain</b> is the name,
+3 -1
View File
@@ -111,8 +111,10 @@
#define LD_PROCESS (1u<<26)
/** Pluggable Transports. */
#define LD_PT (1u<<27)
/** Bootstrap tracker. */
#define LD_BTRACK (1u<<28)
/** Number of logging domains in the code. */
#define N_LOGGING_DOMAINS 28
#define N_LOGGING_DOMAINS 29
/** This log message is not safe to send to a callback-based logger
* immediately. Used as a flag, not a log domain. */
+1
View File
@@ -94,6 +94,7 @@ src_test_test_SOURCES += \
src/test/test_address.c \
src/test/test_address_set.c \
src/test/test_bridges.c \
src/test/test_btrack.c \
src/test/test_buffers.c \
src/test/test_bwmgt.c \
src/test/test_cell_formats.c \
+1
View File
@@ -857,6 +857,7 @@ struct testgroup_t testgroups[] = {
{ "consdiffmgr/", consdiffmgr_tests },
{ "container/", container_tests },
{ "control/", controller_tests },
{ "control/btrack/", btrack_tests },
{ "control/event/", controller_event_tests },
{ "crypto/", crypto_tests },
{ "crypto/ope/", crypto_ope_tests },
+1
View File
@@ -180,6 +180,7 @@ extern struct testcase_t addr_tests[];
extern struct testcase_t address_set_tests[];
extern struct testcase_t address_tests[];
extern struct testcase_t bridges_tests[];
extern struct testcase_t btrack_tests[];
extern struct testcase_t buffer_tests[];
extern struct testcase_t bwmgt_tests[];
extern struct testcase_t cell_format_tests[];
+100
View File
@@ -0,0 +1,100 @@
/* Copyright (c) 2013-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "core/or/or.h"
#include "test/test.h"
#include "test/log_test_helpers.h"
#define OCIRC_EVENT_PRIVATE
#define ORCONN_EVENT_PRIVATE
#include "core/or/ocirc_event.h"
#include "core/or/orconn_event.h"
static void
test_btrack_launch(void *arg)
{
orconn_event_msg_t conn;
ocirc_event_msg_t circ;
(void)arg;
conn.type = ORCONN_MSGTYPE_STATE;
conn.u.state.gid = 1;
conn.u.state.chan = 1;
conn.u.state.proxy_type = PROXY_NONE;
conn.u.state.state = OR_CONN_STATE_CONNECTING;
setup_full_capture_of_logs(LOG_DEBUG);
orconn_event_publish(&conn);
expect_log_msg_containing("ORCONN gid=1 chan=1 proxy_type=0 state=1");
expect_no_log_msg_containing("ORCONN BEST_");
teardown_capture_of_logs();
circ.type = OCIRC_MSGTYPE_CHAN;
circ.u.chan.chan = 1;
circ.u.chan.onehop = true;
setup_full_capture_of_logs(LOG_DEBUG);
ocirc_event_publish(&circ);
expect_log_msg_containing("ORCONN LAUNCH chan=1 onehop=1");
expect_log_msg_containing("ORCONN BEST_ANY state -1->1 gid=1");
teardown_capture_of_logs();
conn.u.state.gid = 2;
conn.u.state.chan = 2;
setup_full_capture_of_logs(LOG_DEBUG);
orconn_event_publish(&conn);
expect_log_msg_containing("ORCONN gid=2 chan=2 proxy_type=0 state=1");
expect_no_log_msg_containing("ORCONN BEST_");
teardown_capture_of_logs();
circ.u.chan.chan = 2;
circ.u.chan.onehop = false;
setup_full_capture_of_logs(LOG_DEBUG);
ocirc_event_publish(&circ);
expect_log_msg_containing("ORCONN LAUNCH chan=2 onehop=0");
expect_log_msg_containing("ORCONN BEST_AP state -1->1 gid=2");
teardown_capture_of_logs();
done:
;
}
static void
test_btrack_delete(void *arg)
{
orconn_event_msg_t conn;
(void)arg;
conn.type = ORCONN_MSGTYPE_STATE;
conn.u.state.gid = 1;
conn.u.state.chan = 1;
conn.u.state.proxy_type = PROXY_NONE;
conn.u.state.state = OR_CONN_STATE_CONNECTING;
setup_full_capture_of_logs(LOG_DEBUG);
orconn_event_publish(&conn);
expect_log_msg_containing("ORCONN gid=1 chan=1 proxy_type=0");
teardown_capture_of_logs();
conn.type = ORCONN_MSGTYPE_STATUS;
conn.u.status.gid = 1;
conn.u.status.status = OR_CONN_EVENT_CLOSED;
conn.u.status.reason = 0;
setup_full_capture_of_logs(LOG_DEBUG);
orconn_event_publish(&conn);
expect_log_msg_containing("ORCONN DELETE gid=1 status=3 reason=0");
teardown_capture_of_logs();
done:
;
}
struct testcase_t btrack_tests[] = {
{ "launch", test_btrack_launch, TT_FORK, 0, NULL },
{ "delete", test_btrack_delete, TT_FORK, 0, NULL },
END_OF_TESTCASES
};
+154 -9
View File
@@ -4,10 +4,14 @@
#define CONNECTION_PRIVATE
#define TOR_CHANNEL_INTERNAL_
#define CONTROL_PRIVATE
#define OCIRC_EVENT_PRIVATE
#define ORCONN_EVENT_PRIVATE
#include "core/or/or.h"
#include "core/or/channel.h"
#include "core/or/channeltls.h"
#include "core/or/circuitlist.h"
#include "core/or/ocirc_event.h"
#include "core/or/orconn_event.h"
#include "core/mainloop/connection.h"
#include "feature/control/control.h"
#include "test/test.h"
@@ -351,10 +355,10 @@ test_cntev_dirboot_defer_desc(void *arg)
/* This event should get deferred */
control_event_boot_dir(BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS, 0);
assert_bootmsg("0 TAG=starting");
control_event_bootstrap(BOOTSTRAP_STATUS_CONN_DIR, 0);
assert_bootmsg("5 TAG=conn_dir");
control_event_bootstrap(BOOTSTRAP_STATUS_CONN, 0);
assert_bootmsg("5 TAG=conn");
control_event_bootstrap(BOOTSTRAP_STATUS_HANDSHAKE, 0);
assert_bootmsg("10 TAG=handshake_dir");
assert_bootmsg("14 TAG=handshake");
/* The deferred event should appear */
control_event_boot_first_orconn();
assert_bootmsg("45 TAG=requesting_descriptors");
@@ -374,21 +378,159 @@ test_cntev_dirboot_defer_orconn(void *arg)
control_event_bootstrap(BOOTSTRAP_STATUS_STARTING, 0);
assert_bootmsg("0 TAG=starting");
/* This event should get deferred */
control_event_boot_dir(BOOTSTRAP_STATUS_CONN_OR, 0);
control_event_boot_dir(BOOTSTRAP_STATUS_ENOUGH_DIRINFO, 0);
assert_bootmsg("0 TAG=starting");
control_event_bootstrap(BOOTSTRAP_STATUS_CONN_DIR, 0);
assert_bootmsg("5 TAG=conn_dir");
control_event_bootstrap(BOOTSTRAP_STATUS_CONN, 0);
assert_bootmsg("5 TAG=conn");
control_event_bootstrap(BOOTSTRAP_STATUS_HANDSHAKE, 0);
assert_bootmsg("10 TAG=handshake_dir");
assert_bootmsg("14 TAG=handshake");
/* The deferred event should appear */
control_event_boot_first_orconn();
assert_bootmsg("80 TAG=conn_or");
assert_bootmsg("75 TAG=enough_dirinfo");
done:
tor_free(saved_event_str);
UNMOCK(queue_control_event_string);
}
#define TEST(name, flags) \
static void
setup_orconn_state(orconn_event_msg_t *msg, uint64_t gid, uint64_t chan,
int proxy_type)
{
msg->type = ORCONN_MSGTYPE_STATE;
msg->u.state.gid = gid;
msg->u.state.chan = chan;
msg->u.state.proxy_type = proxy_type;
}
static void
send_orconn_state(orconn_event_msg_t *msg, uint8_t state)
{
msg->u.state.state = state;
orconn_event_publish(msg);
}
static void
send_ocirc_chan(uint32_t gid, uint64_t chan, bool onehop)
{
ocirc_event_msg_t msg;
msg.type = OCIRC_MSGTYPE_CHAN;
msg.u.chan.gid = gid;
msg.u.chan.chan = chan;
msg.u.chan.onehop = onehop;
ocirc_event_publish(&msg);
}
static void
test_cntev_orconn_state(void *arg)
{
orconn_event_msg_t conn;
(void)arg;
MOCK(queue_control_event_string, mock_queue_control_event_string);
control_testing_set_global_event_mask(EVENT_MASK_(EVENT_STATUS_CLIENT));
setup_orconn_state(&conn, 1, 1, PROXY_NONE);
send_orconn_state(&conn, OR_CONN_STATE_CONNECTING);
send_ocirc_chan(1, 1, true);
assert_bootmsg("5 TAG=conn");
send_orconn_state(&conn, OR_CONN_STATE_TLS_HANDSHAKING);
assert_bootmsg("10 TAG=conn_done");
send_orconn_state(&conn, OR_CONN_STATE_OR_HANDSHAKING_V3);
assert_bootmsg("14 TAG=handshake");
send_orconn_state(&conn, OR_CONN_STATE_OPEN);
assert_bootmsg("15 TAG=handshake_done");
conn.u.state.gid = 2;
conn.u.state.chan = 2;
send_orconn_state(&conn, OR_CONN_STATE_CONNECTING);
/* It doesn't know it's an origin circuit yet */
assert_bootmsg("15 TAG=handshake_done");
send_ocirc_chan(2, 2, false);
assert_bootmsg("80 TAG=ap_conn");
send_orconn_state(&conn, OR_CONN_STATE_TLS_HANDSHAKING);
assert_bootmsg("85 TAG=ap_conn_done");
send_orconn_state(&conn, OR_CONN_STATE_OR_HANDSHAKING_V3);
assert_bootmsg("89 TAG=ap_handshake");
send_orconn_state(&conn, OR_CONN_STATE_OPEN);
assert_bootmsg("90 TAG=ap_handshake_done");
done:
tor_free(saved_event_str);
UNMOCK(queue_control_event_string);
}
static void
test_cntev_orconn_state_pt(void *arg)
{
orconn_event_msg_t conn;
(void)arg;
MOCK(queue_control_event_string, mock_queue_control_event_string);
control_testing_set_global_event_mask(EVENT_MASK_(EVENT_STATUS_CLIENT));
setup_orconn_state(&conn, 1, 1, PROXY_PLUGGABLE);
send_ocirc_chan(1, 1, true);
send_orconn_state(&conn, OR_CONN_STATE_CONNECTING);
assert_bootmsg("1 TAG=conn_pt");
send_orconn_state(&conn, OR_CONN_STATE_PROXY_HANDSHAKING);
assert_bootmsg("2 TAG=conn_done_pt");
send_orconn_state(&conn, OR_CONN_STATE_TLS_HANDSHAKING);
assert_bootmsg("10 TAG=conn_done");
send_orconn_state(&conn, OR_CONN_STATE_OR_HANDSHAKING_V3);
assert_bootmsg("14 TAG=handshake");
send_orconn_state(&conn, OR_CONN_STATE_OPEN);
assert_bootmsg("15 TAG=handshake_done");
send_ocirc_chan(2, 2, false);
conn.u.state.gid = 2;
conn.u.state.chan = 2;
send_orconn_state(&conn, OR_CONN_STATE_CONNECTING);
assert_bootmsg("76 TAG=ap_conn_pt");
send_orconn_state(&conn, OR_CONN_STATE_PROXY_HANDSHAKING);
assert_bootmsg("77 TAG=ap_conn_done_pt");
done:
tor_free(saved_event_str);
UNMOCK(queue_control_event_string);
}
static void
test_cntev_orconn_state_proxy(void *arg)
{
orconn_event_msg_t conn;
(void)arg;
MOCK(queue_control_event_string, mock_queue_control_event_string);
control_testing_set_global_event_mask(EVENT_MASK_(EVENT_STATUS_CLIENT));
setup_orconn_state(&conn, 1, 1, PROXY_CONNECT);
send_ocirc_chan(1, 1, true);
send_orconn_state(&conn, OR_CONN_STATE_CONNECTING);
assert_bootmsg("3 TAG=conn_proxy");
send_orconn_state(&conn, OR_CONN_STATE_PROXY_HANDSHAKING);
assert_bootmsg("4 TAG=conn_done_proxy");
send_orconn_state(&conn, OR_CONN_STATE_TLS_HANDSHAKING);
assert_bootmsg("10 TAG=conn_done");
send_orconn_state(&conn, OR_CONN_STATE_OR_HANDSHAKING_V3);
assert_bootmsg("14 TAG=handshake");
send_orconn_state(&conn, OR_CONN_STATE_OPEN);
assert_bootmsg("15 TAG=handshake_done");
send_ocirc_chan(2, 2, false);
conn.u.state.gid = 2;
conn.u.state.chan = 2;
send_orconn_state(&conn, OR_CONN_STATE_CONNECTING);
assert_bootmsg("78 TAG=ap_conn_proxy");
send_orconn_state(&conn, OR_CONN_STATE_PROXY_HANDSHAKING);
assert_bootmsg("79 TAG=ap_conn_done_proxy");
done:
tor_free(saved_event_str);
UNMOCK(queue_control_event_string);
}
#define TEST(name, flags) \
{ #name, test_cntev_ ## name, flags, 0, NULL }
struct testcase_t controller_event_tests[] = {
@@ -398,5 +540,8 @@ struct testcase_t controller_event_tests[] = {
TEST(event_mask, TT_FORK),
TEST(dirboot_defer_desc, TT_FORK),
TEST(dirboot_defer_orconn, TT_FORK),
TEST(orconn_state, TT_FORK),
TEST(orconn_state_pt, TT_FORK),
TEST(orconn_state_proxy, TT_FORK),
END_OF_TESTCASES
};