diff options
-rw-r--r-- | doc/TODO | 17 | ||||
-rw-r--r-- | doc/control-spec.txt | 23 | ||||
-rw-r--r-- | src/or/control.c | 83 | ||||
-rw-r--r-- | src/or/or.h | 2 | ||||
-rw-r--r-- | src/or/relay.c | 28 |
5 files changed, 131 insertions, 22 deletions
@@ -62,7 +62,7 @@ N . Switch to libevent R o Reset uptime when IP changes. Functionality -N . Implement pending controller features. + o Implement pending controller features. o Stubs for new functions. o GETINFO o Version @@ -84,9 +84,9 @@ N . Implement pending controller features. o Event for "new descriptors" o Better stream IDs o Stream status changed: "new" state. - - EXTENDCIRCUIT -R - revised circ selection stuff. - - Implement controller interface. + o EXTENDCIRCUIT + o revised circ selection stuff. + o Implement controller interface. o ATTACHSTREAM o Make streams have an 'unattached and not-automatically-attachable' state. ("Controller managed.") @@ -96,8 +96,13 @@ R - revised circ selection stuff. o Time out never-attached streams. o If we never get a CONNECTED back, we should put the stream back in CONTROLLER_WAIT, not in CIRCUIT_WAIT. - - Add a way for the controller to say, "Hey, nuke this stream." - - Tests for new controller features + o Add a way for the controller to say, "Hey, nuke this stream." + o Specify + o Implement + o Add a way for the controller to say, "Hey, nuke this circuit." + o Specify + o Implement + - Tests for new controller features R o HTTPS proxy for OR CONNECT stuff. (For outgoing SSL connections to other ORs.) o Changes for forward compatibility diff --git a/doc/control-spec.txt b/doc/control-spec.txt index b1092eeb34..ed7ec4bfd5 100644 --- a/doc/control-spec.txt +++ b/doc/control-spec.txt @@ -417,6 +417,29 @@ the message. after a new stream event is received, and before attaching this stream to a circuit. +3.20 CLOSESTREAM (Type 0x0013) + + Sent from the client to the server. The message body contains three + fields: + Stream ID [4 octets] + Reason [1 octet] + Flags [1 octet] + + Tells the server to close the specified stream. The reason should be one + of the Tor RELAY_END reasons given in tor-spec.txt. If the LSB of the + flags field is nonzero, and the stream wants to write data, Tor tries to + hold the stream open for a while until it can be flushed. + +3.21 CLOSECIRCUIT (Type 0x0014) + + Sent from the client to the server. The message body contains two + fields: + Circuit ID [4 octets] + Flags [1 octet] + + Tells the server to close the specified circuit. If the LSB of the flags + field is nonzero, do not close the circuit unless it is unused. + 4. Implementation notes 4.1. There are four ways we could authenticate, for now: diff --git a/src/or/control.c b/src/or/control.c index a655521ec9..3114dbf2d3 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -48,8 +48,10 @@ const char control_c_id[] = "$Id$"; #define CONTROL_CMD_POSTDESCRIPTOR 0x000F #define CONTROL_CMD_FRAGMENTHEADER 0x0010 #define CONTROL_CMD_FRAGMENT 0x0011 -#define CONTROL_CMD_REDIRECTSTREAM 0x0012 -#define _CONTROL_CMD_MAX_RECOGNIZED 0x0012 +#define CONTROL_CMD_REDIRECTSTREAM 0x0012 +#define CONTROL_CMD_CLOSESTREAM 0x0013 +#define CONTROL_CMD_CLOSECIRCUIT 0x0014 +#define _CONTROL_CMD_MAX_RECOGNIZED 0x0014 /* Recognized error codes. */ #define ERR_UNSPECIFIED 0x0000 @@ -152,6 +154,10 @@ static int handle_control_postdescriptor(connection_t *conn, uint32_t len, const char *body); static int handle_control_redirectstream(connection_t *conn, uint32_t len, const char *body); +static int handle_control_closestream(connection_t *conn, uint32_t len, + const char *body); +static int handle_control_closecircuit(connection_t *conn, uint32_t len, + const char *body); /** Given a possibly invalid message type code <b>cmd</b>, return a * human-readable string equivalent. */ @@ -772,7 +778,72 @@ handle_control_redirectstream(connection_t *conn, uint32_t len, send_control_done(conn); return 0; } +static int +handle_control_closestream(connection_t *conn, uint32_t len, + const char *body) +{ + uint32_t conn_id; + connection_t *ap_conn; + uint8_t reason; + int hold_open; + + if (len < 6) { + send_control_error(conn, ERR_SYNTAX, "closestream message too short"); + return 0; + } + + conn_id = ntohl(get_uint32(body)); + reason = *(uint8_t*)(body+4); + hold_open = (*(uint8_t*)(body+5)) & 1; + + if (!(ap_conn = connection_get_by_global_id(conn_id)) + || ap_conn->state != CONN_TYPE_AP + || !ap_conn->socks_request) { + send_control_error(conn, ERR_NO_STREAM, + "No AP connection found with given ID"); + return 0; + } + + if (!ap_conn->socks_request->has_finished) { + socks5_reply_status_t status = + connection_edge_end_reason_socks5_response(reason); + connection_ap_handshake_socks_reply(ap_conn, NULL, 0, status); + } + if (hold_open) + ap_conn->hold_open_until_flushed = 1; + connection_mark_for_close(ap_conn); + + send_control_done(conn); + return 0; +} +static int +handle_control_closecircuit(connection_t *conn, uint32_t len, + const char *body) +{ + uint32_t circ_id; + circuit_t *circ; + int safe; + if (len < 5) { + send_control_error(conn, ERR_SYNTAX, "closecircuit message too short"); + return 0; + } + circ_id = ntohl(get_uint32(body)); + safe = (*(uint8_t*)(body+4)) & 1; + + if (!(circ = circuit_get_by_global_id(circ_id))) { + send_control_error(conn, ERR_NO_CIRC, + "No circuit found with given ID"); + return 0; + } + + if (!safe || !circ->p_streams) { + circuit_mark_for_close(circ); + } + + send_control_done(conn); + return 0; +} /** Called when <b>conn</b> has no more bytes left on its outbuf. */ int @@ -882,6 +953,14 @@ connection_control_process_inbuf(connection_t *conn) { if (handle_control_redirectstream(conn, body_len, body)) return -1; break; + case CONTROL_CMD_CLOSESTREAM: + if (handle_control_closestream(conn, body_len, body)) + return -1; + break; + case CONTROL_CMD_CLOSECIRCUIT: + if (handle_control_closecircuit(conn, body_len, body)) + return -1; + break; case CONTROL_CMD_ERROR: case CONTROL_CMD_DONE: case CONTROL_CMD_CONFVALUE: diff --git a/src/or/or.h b/src/or/or.h index 19efee2760..c4e7f4f28d 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1560,7 +1560,7 @@ int connection_edge_send_command(connection_t *fromconn, circuit_t *circ, size_t payload_len, crypt_path_t *cpath_layer); int connection_edge_package_raw_inbuf(connection_t *conn, int package_partial); void connection_edge_consider_sending_sendme(connection_t *conn); -socks5_reply_status_t connection_edge_end_reason_sock5_response(char *payload, uint16_t length); +socks5_reply_status_t connection_edge_end_reason_socks5_response(int reason); int errno_to_end_reason(int e); extern uint64_t stats_n_data_cells_packaged; diff --git a/src/or/relay.c b/src/or/relay.c index 5fd5be9097..5651fd35e1 100644 --- a/src/or/relay.c +++ b/src/or/relay.c @@ -476,16 +476,13 @@ connection_edge_end_reason_str(char *payload, uint16_t length) { } } -/** Translate the <b>payload</b> of length <b>length</b>, which - * came from a relay 'end' cell, into an appropriate SOCKS5 reply code. +/** Translate <b>reason</b> (as from a relay 'end' cell) into an + * appropriate SOCKS5 reply code. */ -static socks5_reply_status_t -connection_edge_end_reason_socks5_response(char *payload, uint16_t length) { - if (length < 1) { - log_fn(LOG_WARN,"End cell arrived with length 0. Should be at least 1."); - return SOCKS5_GENERAL_ERROR; - } - switch (*payload) { +socks5_reply_status_t +connection_edge_end_reason_socks5_response(int reason) +{ + switch (reason) { case END_STREAM_REASON_MISC: return SOCKS5_GENERAL_ERROR; case END_STREAM_REASON_RESOLVEFAILED: @@ -511,7 +508,7 @@ connection_edge_end_reason_socks5_response(char *payload, uint16_t length) { case END_STREAM_REASON_TORPROTOCOL: return SOCKS5_GENERAL_ERROR; default: - log_fn(LOG_WARN,"Reason for ending (%d) not recognized.",*payload); + log_fn(LOG_WARN,"Reason for ending (%d) not recognized.",reason); return SOCKS5_GENERAL_ERROR; } } @@ -817,9 +814,14 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, rh.length), conn->stream_id, (int)conn->stream_size); if (conn->socks_request && !conn->socks_request->has_finished) { - socks5_reply_status_t status = - connection_edge_end_reason_socks5_response( - cell->payload+RELAY_HEADER_SIZE, rh.length); + socks5_reply_status_t status; + if (rh.length < 1) { + log_fn(LOG_WARN,"End cell arrived with length 0. Should be at least 1."); + status = SOCKS5_GENERAL_ERROR; + } else { + status = connection_edge_end_reason_socks5_response( + *(uint8_t*)cell->payload+RELAY_HEADER_SIZE); + } connection_ap_handshake_socks_reply(conn, NULL, 0, status); } #ifdef HALF_OPEN |