summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRoger Dingledine <arma@torproject.org>2007-04-30 11:10:45 +0000
committerRoger Dingledine <arma@torproject.org>2007-04-30 11:10:45 +0000
commit5ba4eaba1cfe1858cc152a9945d0bb6c2d1838b4 (patch)
treeb92b562a0567adea1d6b2855e5ad1243f7aa53fb /src
parent2711ac2f6265eb981f1f7b5679fecd6af8682c3c (diff)
downloadtor-5ba4eaba1cfe1858cc152a9945d0bb6c2d1838b4.tar.gz
tor-5ba4eaba1cfe1858cc152a9945d0bb6c2d1838b4.zip
Let the controller specify HOP=%d as an argument to ATTACHSTREAM,
so we can exit from the middle of the circuit. svn:r10056
Diffstat (limited to 'src')
-rw-r--r--src/or/circuitlist.c16
-rw-r--r--src/or/circuituse.c24
-rw-r--r--src/or/connection_edge.c13
-rw-r--r--src/or/control.c29
-rw-r--r--src/or/or.h7
5 files changed, 68 insertions, 21 deletions
diff --git a/src/or/circuitlist.c b/src/or/circuitlist.c
index 73ca7e1fa0..839d2b6dc7 100644
--- a/src/or/circuitlist.c
+++ b/src/or/circuitlist.c
@@ -844,6 +844,22 @@ circuit_get_cpath_len(origin_circuit_t *circ)
return n;
}
+/** Return the <b>hopnum</b>th hop in <b>circ</b>->cpath, or NULL if there
+ * aren't that many hops in the list. */
+crypt_path_t *
+circuit_get_cpath_hop(origin_circuit_t *circ, int hopnum)
+{
+ if (circ && circ->cpath) {
+ crypt_path_t *cpath, *cpath_next = NULL;
+ for (cpath = circ->cpath; cpath_next != circ->cpath; cpath = cpath_next) {
+ cpath_next = cpath->next;
+ if (--hopnum <= 0)
+ return cpath;
+ }
+ }
+ return NULL;
+}
+
/** Go through the circuitlist; mark-for-close each circuit that starts
* at us but has not yet been used. */
void
diff --git a/src/or/circuituse.c b/src/or/circuituse.c
index 6bfe087100..c2faa109b5 100644
--- a/src/or/circuituse.c
+++ b/src/or/circuituse.c
@@ -1101,7 +1101,8 @@ circuit_get_open_circ_or_launch(edge_connection_t *conn,
* circ's cpath.
*/
static void
-link_apconn_to_circ(edge_connection_t *apconn, origin_circuit_t *circ)
+link_apconn_to_circ(edge_connection_t *apconn, origin_circuit_t *circ,
+ crypt_path_t *cpath)
{
/* add it into the linked list of streams on this circuit */
log_debug(LD_APP|LD_CIRC, "attaching new conn to circ. n_circ_id %d.",
@@ -1113,10 +1114,14 @@ link_apconn_to_circ(edge_connection_t *apconn, origin_circuit_t *circ)
/* assert_connection_ok(conn, time(NULL)); */
circ->p_streams = apconn;
- tor_assert(circ->cpath);
- tor_assert(circ->cpath->prev);
- tor_assert(circ->cpath->prev->state == CPATH_STATE_OPEN);
- apconn->cpath_layer = circ->cpath->prev;
+ if (cpath) { /* we were given one; use it */
+ apconn->cpath_layer = cpath;
+ } else { /* use the last hop in the circuit */
+ tor_assert(circ->cpath);
+ tor_assert(circ->cpath->prev);
+ tor_assert(circ->cpath->prev->state == CPATH_STATE_OPEN);
+ apconn->cpath_layer = circ->cpath->prev;
+ }
}
/** If an exit wasn't specifically chosen, save the history for future
@@ -1172,7 +1177,8 @@ consider_recording_trackhost(edge_connection_t *conn, origin_circuit_t *circ)
* for connection_ap_handshake_attach_circuit. */
int
connection_ap_handshake_attach_chosen_circuit(edge_connection_t *conn,
- origin_circuit_t *circ)
+ origin_circuit_t *circ,
+ crypt_path_t *cpath)
{
tor_assert(conn);
tor_assert(conn->_base.state == AP_CONN_STATE_CIRCUIT_WAIT ||
@@ -1186,7 +1192,7 @@ connection_ap_handshake_attach_chosen_circuit(edge_connection_t *conn,
if (!circ->_base.timestamp_dirty)
circ->_base.timestamp_dirty = time(NULL);
- link_apconn_to_circ(conn, circ);
+ link_apconn_to_circ(conn, circ, cpath);
tor_assert(conn->socks_request);
switch (conn->socks_request->command) {
case SOCKS_COMMAND_CONNECT:
@@ -1269,7 +1275,7 @@ connection_ap_handshake_attach_circuit(edge_connection_t *conn)
circuit_log_path(LOG_INFO,LD_APP|LD_CIRC,circ);
/* We have found a suitable circuit for our conn. Hurray. */
- return connection_ap_handshake_attach_chosen_circuit(conn, circ);
+ return connection_ap_handshake_attach_chosen_circuit(conn, circ, NULL);
} else { /* we're a rendezvous conn */
origin_circuit_t *rendcirc=NULL, *introcirc=NULL;
@@ -1295,7 +1301,7 @@ connection_ap_handshake_attach_circuit(edge_connection_t *conn)
* feasibility, at this point.
*/
rendcirc->_base.timestamp_dirty = time(NULL);
- link_apconn_to_circ(conn, rendcirc);
+ link_apconn_to_circ(conn, rendcirc, NULL);
if (connection_ap_handshake_send_begin(conn) < 0)
return 0; /* already marked, let them fade away */
return 1;
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c
index 0e5aa8fd72..035eecafc1 100644
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@ -1181,7 +1181,8 @@ addressmap_get_mappings(smartlist_t *sl, time_t min_expires,
*/
int
connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
- origin_circuit_t *circ)
+ origin_circuit_t *circ,
+ crypt_path_t *cpath)
{
socks_request_t *socks = conn->socks_request;
hostname_type_t addresstype;
@@ -1337,8 +1338,8 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
tor_fragile_assert();
}
conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
- if ((circ &&
- connection_ap_handshake_attach_chosen_circuit(conn, circ) < 0) ||
+ if ((circ && connection_ap_handshake_attach_chosen_circuit(
+ conn, circ, cpath) < 0) ||
(!circ &&
connection_ap_handshake_attach_circuit(conn) < 0)) {
connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH);
@@ -1583,7 +1584,7 @@ connection_ap_handshake_process_socks(edge_connection_t *conn)
conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT;
return 0;
}
- return connection_ap_handshake_rewrite_and_attach(conn, NULL);
+ return connection_ap_handshake_rewrite_and_attach(conn, NULL, NULL);
}
/** connection_init_accepted_conn() found a new trans AP conn.
@@ -1625,7 +1626,7 @@ connection_ap_process_transparent(edge_connection_t *conn)
conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT;
return 0;
}
- return connection_ap_handshake_rewrite_and_attach(conn, NULL);
+ return connection_ap_handshake_rewrite_and_attach(conn, NULL, NULL);
}
/** connection_edge_process_inbuf() found a conn in state natd_wait. See if
@@ -1704,7 +1705,7 @@ connection_ap_process_natd(edge_connection_t *conn)
}
conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
- return connection_ap_handshake_rewrite_and_attach(conn, NULL);
+ return connection_ap_handshake_rewrite_and_attach(conn, NULL, NULL);
}
/** Iterate over the two bytes of stream_id until we get one that is not
diff --git a/src/or/control.c b/src/or/control.c
index beeb1727fb..f965b7035a 100644
--- a/src/or/control.c
+++ b/src/or/control.c
@@ -1897,6 +1897,8 @@ handle_control_attachstream(control_connection_t *conn, uint32_t len,
origin_circuit_t *circ = NULL;
int zero_circ;
smartlist_t *args;
+ crypt_path_t *cpath=NULL;
+ int hop=0, hop_line_ok=1;
(void) len;
args = getargs_helper("ATTACHSTREAM", conn, body, 2, -1);
@@ -1911,10 +1913,20 @@ handle_control_attachstream(control_connection_t *conn, uint32_t len,
} else if (!zero_circ && !(circ = get_circ(smartlist_get(args, 1)))) {
connection_printf_to_buf(conn, "552 Unknown circuit \"%s\"\r\n",
(char*)smartlist_get(args, 1));
+ } else if (circ && smartlist_len(args) > 2) {
+ char *hopstring = smartlist_get(args, 2);
+ if (!strcasecmpstart(hopstring, "HOP=")) {
+ hopstring += strlen("HOP=");
+ hop = tor_parse_ulong(hopstring, 10, 0, ULONG_MAX,
+ &hop_line_ok, NULL);
+ if (!hop_line_ok) { /* broken hop line */
+ connection_printf_to_buf(conn, "552 Bad value hop=%s\r\n", hopstring);
+ }
+ }
}
SMARTLIST_FOREACH(args, char *, cp, tor_free(cp));
smartlist_free(args);
- if (!ap_conn || (!zero_circ && !circ))
+ if (!ap_conn || (!zero_circ && !circ) || !hop_line_ok)
return 0;
if (ap_conn->_base.state != AP_CONN_STATE_CONTROLLER_WAIT &&
@@ -1940,16 +1952,25 @@ handle_control_attachstream(control_connection_t *conn, uint32_t len,
if (circ && (circ->_base.state != CIRCUIT_STATE_OPEN)) {
connection_write_str_to_buf(
- "551 Can't attach stream to non-open, origin circuit\r\n",
+ "551 Can't attach stream to non-open origin circuit\r\n",
conn);
return 0;
}
- if (circ && circuit_get_cpath_len(circ) < 2) {
+ if (circ && (circuit_get_cpath_len(circ)<2 || hop==1)) {
connection_write_str_to_buf(
"551 Can't attach stream to one-hop circuit.\r\n", conn);
return 0;
}
- if (connection_ap_handshake_rewrite_and_attach(ap_conn, circ) < 0) {
+ if (circ && hop>0) {
+ /* find this hop in the circuit, and set cpath */
+ cpath = circuit_get_cpath_hop(circ, hop);
+ if (!cpath) {
+ connection_printf_to_buf(conn,
+ "551 Circuit doesn't have %d hops.\r\n", hop);
+ return 0;
+ }
+ }
+ if (connection_ap_handshake_rewrite_and_attach(ap_conn, circ, cpath) < 0) {
connection_write_str_to_buf("551 Unable to attach stream\r\n", conn);
return 0;
}
diff --git a/src/or/or.h b/src/or/or.h
index 91f85f3257..18a09560b4 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -2085,6 +2085,7 @@ void circuit_expire_all_dirty_circs(void);
void _circuit_mark_for_close(circuit_t *circ, int reason,
int line, const char *file);
int circuit_get_cpath_len(origin_circuit_t *circ);
+crypt_path_t *circuit_get_cpath_hop(origin_circuit_t *circ, int hopnum);
void circuit_get_all_pending_on_or_conn(smartlist_t *out,
or_connection_t *or_conn);
int circuit_count_pending_on_or_conn(or_connection_t *or_conn);
@@ -2127,7 +2128,8 @@ origin_circuit_t *circuit_launch_by_router(uint8_t purpose,
int is_internal);
void circuit_reset_failure_count(int timeout);
int connection_ap_handshake_attach_chosen_circuit(edge_connection_t *conn,
- origin_circuit_t *circ);
+ origin_circuit_t *circ,
+ crypt_path_t *cpath);
int connection_ap_handshake_attach_circuit(edge_connection_t *conn);
/********************************* command.c ***************************/
@@ -2322,7 +2324,8 @@ const char *addressmap_register_virtual_address(int type, char *new_address);
void addressmap_get_mappings(smartlist_t *sl, time_t min_expires,
time_t max_expires);
int connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
- origin_circuit_t *circ);
+ origin_circuit_t *circ,
+ crypt_path_t *cpath);
void set_exit_redirects(smartlist_t *lst);
typedef enum hostname_type_t {