Commit 271b50f5 authored by Taylor Yu's avatar Taylor Yu
Browse files

Add ORCONN event pubsub system

Add a publish-subscribe subsystem to publish messages about changes to
OR connections.

connection_or_change_state() in connection_or.c and
control_event_or_conn_event() in control.c publish messages to this
subsystem via helper functions.

Move state constants from connection_or.h to orconn_state.h so that
subscribers don't have to include all of connection_or.h to take
actions based on changes in OR connection state.  Move event constants
from control.h for similar reasons.

Part of ticket 27167.
parent 308dde0c
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
#include "lib/cc/compat_compiler.h"
#include "lib/cc/torint.h"

#include "core/or/orconn_event_sys.h"
#include "lib/compress/compress_sys.h"
#include "lib/crypt_ops/crypto_sys.h"
#include "lib/err/torerr_sys.h"
@@ -35,6 +36,7 @@ const subsys_fns_t *tor_subsystems[] = {
  &sys_compress, /* -70 */
  &sys_crypto, /* -60 */
  &sys_tortls, /* -50 */
  &sys_orconn_event, /* -40 */
};

const unsigned n_tor_subsystems = ARRAY_LENGTH(tor_subsystems);
+3 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ LIBTOR_APP_A_SOURCES = \
	src/core/or/connection_or.c		\
	src/core/or/dos.c			\
	src/core/or/onion.c			\
	src/core/or/orconn_event.c		\
	src/core/or/policies.c			\
	src/core/or/protover.c			\
	src/core/or/protover_rust.c		\
@@ -238,6 +239,8 @@ 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		\
+1 −1
Original line number Diff line number Diff line
@@ -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);
+62 −11
Original line number Diff line number Diff line
@@ -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.
 */
@@ -412,6 +458,7 @@ connection_or_change_state(or_connection_t *conn, uint8_t state)

  conn->base_.state = state;

  connection_or_state_publish(conn, state);
  if (conn->chan)
    channel_tls_handle_state_change_on_orconn(conn->chan, conn, state);
}
@@ -755,7 +802,7 @@ 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,
        connection_or_event_status(or_conn, OR_CONN_EVENT_FAILED,
                                   reason);
        if (!authdir_mode_tests_reachability(options))
          control_event_bootstrap_prob_or(
@@ -766,10 +813,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));
  }
}
@@ -1361,7 +1408,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);
@@ -1468,9 +1515,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. */
@@ -1482,7 +1526,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
@@ -1978,7 +2029,7 @@ 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,
    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(
@@ -2219,7 +2270,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
Original line number Diff line number Diff line
@@ -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);
Loading