diff options
author | Nick Mathewson <nickm@torproject.org> | 2012-03-16 09:40:44 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2013-07-18 14:59:55 -0400 |
commit | 8bf0382b220b31605fb5a542f36a842bdd7a6ed0 (patch) | |
tree | 860c1909b98b9db6587f4e5a3dea14175f86665d /src/or/connection_or.c | |
parent | f45e1fbd5b25735c75bed8767d9d50e279c4b63a (diff) | |
download | tor-8bf0382b220b31605fb5a542f36a842bdd7a6ed0.tar.gz tor-8bf0382b220b31605fb5a542f36a842bdd7a6ed0.zip |
Skeleton ExtORPort implementation. Needs testing, documentation.
Does not implement TransportControlPort yet.
Diffstat (limited to 'src/or/connection_or.c')
-rw-r--r-- | src/or/connection_or.c | 202 |
1 files changed, 199 insertions, 3 deletions
diff --git a/src/or/connection_or.c b/src/or/connection_or.c index 3616363505..a6d1a8d7ec 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -75,6 +75,9 @@ 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; +/**DOCDOC */ +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 +177,52 @@ connection_or_set_identity_digest(or_connection_t *conn, const char *digest) #endif } +void +connection_or_remove_from_ext_or_id_map(or_connection_t *conn) +{ + or_connection_t *tmp; + if (!orconn_identity_map) + orconn_identity_map = digestmap_new(); + + 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); +} + + +/*DOCDOC*/ +void +connection_or_clear_ext_or_id_map(void) +{ + digestmap_free(orconn_ext_or_id_map, NULL); +} + +/*DOCDOC + sets it to a random value */ +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(); + + if (!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)); + + 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 +277,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)); @@ -423,6 +472,23 @@ var_cell_free(var_cell_t *cell) tor_free(cell); } +/*DOCDOC*/ +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; +} + +/*DOCDOC*/ +void +ext_or_cmd_free(ext_or_cmd_t *cmd) +{ + tor_free(cmd); +} + /** We've received an EOF from <b>conn</b>. Mark it for close and return. */ int connection_or_reached_eof(or_connection_t *conn) @@ -1077,7 +1143,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 @@ -1470,7 +1536,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) @@ -2365,3 +2432,132 @@ connection_or_send_authenticate_cell(or_connection_t *conn, int authtype) return 0; } +/*DOCDOC*/ +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); + } +} + +/*DOCDOC*/ +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; +} + +/*DOCDOC*/ +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; + control_event_or_conn_status(conn, OR_CONN_EVENT_NEW, 0); + connection_tls_start_handshake(conn, 1); +} + +/*XXXX make these match the spec .*/ +#define EXT_OR_CMD_DONE 0x0001 +#define EXT_OR_CMD_USERADDR 0x0002 +#define EXT_OR_CMD_WANT_CONTROL 0x0003 +#define EXT_OR_CMD_OKAY 0x1001 + +/*DOCDOC*/ +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; + + while (1) { + command = NULL; + r = connection_fetch_ext_or_cmd_from_buf(conn, &command); + if (r < 0) + return -1; + else if (r == 0) + return 0; /* need to wait for more data */ + + /* Got a command! */ + tor_assert(command); + + if (command->cmd == EXT_OR_CMD_DONE) { + if (connection_get_inbuf_len(conn)) { + /* The inbuf isn't empty; the client is misbehaving. */ + goto err; + } + connection_write_ext_or_command(conn, EXT_OR_CMD_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_USERADDR) { + /* Copy address string. */ + tor_addr_t addr; + uint16_t port; + char *addr_str; + char *address_part=NULL; + int res; + addr_str = tor_malloc(command->len + 1); + memcpy(addr_str, command->body, command->len); + addr_str[command->len] = 0; + + res = tor_addr_port_split(LOG_INFO, addr_str, &address_part, &port); + tor_free(addr_str); + if (res<0) + goto err; + + res = tor_addr_parse(&addr, address_part); + tor_free(address_part); + if (res<0) + goto err; + + /* record the address */ + tor_addr_copy(&conn->addr, &addr); + conn->port = port; + } else if (command->cmd == EXT_OR_CMD_WANT_CONTROL) { + char response[128]; + char *cp; + memcpy(response, or_conn->ext_or_conn_id, EXT_OR_CONN_ID_LEN); + cp = response+EXT_OR_CONN_ID_LEN; + /* XXXX write the TransportControlPort; advance cp. */ + connection_write_ext_or_command(conn, EXT_OR_CMD_OKAY, response, + cp-response); + } + + ext_or_cmd_free(command); + } + + err: + ext_or_cmd_free(command); + return -1; +} + +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; +} |