diff options
author | Roger Dingledine <arma@torproject.org> | 2004-04-05 00:47:48 +0000 |
---|---|---|
committer | Roger Dingledine <arma@torproject.org> | 2004-04-05 00:47:48 +0000 |
commit | 7793078dffae64d8d4574a37c6ffa40fb54637c9 (patch) | |
tree | b988080813729ccd28d572bce44e032398bec00a /src/or/connection_edge.c | |
parent | a9813f0210bbf723e19b24c73fb93ecc436efcfb (diff) | |
download | tor-7793078dffae64d8d4574a37c6ffa40fb54637c9.tar tor-7793078dffae64d8d4574a37c6ffa40fb54637c9.tar.gz |
alice can now look up bob's service descriptor,
choose an intro point, connect to it,
choose a rend point, connect to it and establish a cookie,
get an ack from the rendezvous point,
and know when both circs are ready for her.
APConns don't use conn->purpose anymore
don't initiate a renddesc lookup if one is already in progress
also fix a buffer overflow in nickname parsing (only exploitable
by the operator though)
svn:r1471
Diffstat (limited to 'src/or/connection_edge.c')
-rw-r--r-- | src/or/connection_edge.c | 184 |
1 files changed, 108 insertions, 76 deletions
diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 04bf1794f..d726549db 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -76,6 +76,7 @@ int connection_edge_process_inbuf(connection_t *conn) { case AP_CONN_STATE_OPEN: case EXIT_CONN_STATE_OPEN: if(conn->package_window <= 0) { + /* XXX this is still getting called rarely :( */ log_fn(LOG_WARN,"called with package_window %d. Tell Roger.", conn->package_window); return 0; } @@ -85,6 +86,7 @@ int connection_edge_process_inbuf(connection_t *conn) { } return 0; case EXIT_CONN_STATE_CONNECTING: + case AP_CONN_STATE_RENDDESC_WAIT: case AP_CONN_STATE_CIRCUIT_WAIT: case AP_CONN_STATE_CONNECT_WAIT: log_fn(LOG_INFO,"data from edge while in '%s' state. Leaving it on buffer.", @@ -235,6 +237,7 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, if(conn && conn->state != AP_CONN_STATE_OPEN && conn->state != EXIT_CONN_STATE_OPEN) { if(rh.command == RELAY_COMMAND_END) { + circuit_log_path(LOG_INFO,circ); log_fn(LOG_INFO,"Edge got end (%s) before we're connected. Marking for close.", connection_edge_end_reason(cell->payload+RELAY_HEADER_SIZE, rh.length)); conn->has_sent_end = 1; /* we just got an 'end', don't need to send one */ @@ -335,9 +338,7 @@ int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, */ addr = ntohl(get_uint32(cell->payload+RELAY_HEADER_SIZE+1)); client_dns_set_entry(conn->socks_request->address, addr); - /* conn->purpose is still set to general */ conn->state = AP_CONN_STATE_CIRCUIT_WAIT; - /* attaching to a dirty circuit is fine */ if(connection_ap_handshake_attach_circuit(conn) >= 0) return 0; /* else, conn will get closed below */ @@ -491,6 +492,7 @@ int connection_edge_finished_flushing(connection_t *conn) { connection_edge_consider_sending_sendme(conn); return 0; case AP_CONN_STATE_SOCKS_WAIT: + case AP_CONN_STATE_RENDDESC_WAIT: case AP_CONN_STATE_CIRCUIT_WAIT: case AP_CONN_STATE_CONNECT_WAIT: connection_stop_writing(conn); @@ -609,7 +611,6 @@ void connection_ap_expire_beginning(void) { conn->has_sent_end = 0; /* move it back into 'pending' state. */ conn->state = AP_CONN_STATE_CIRCUIT_WAIT; - /* conn->purpose is still set to general */ circuit_detach_stream(circ, conn); /* kludge to make us not try this circuit again, yet to allow * current streams on it to survive if they can: make it @@ -642,7 +643,6 @@ void connection_ap_attach_pending(void) if (conn->type != CONN_TYPE_AP || conn->state != AP_CONN_STATE_CIRCUIT_WAIT) continue; - /* attaching to a dirty circuit is fine */ if(connection_ap_handshake_attach_circuit(conn) < 0) { /* -1 means it will never work */ /* Don't send end; there is no 'other side' yet */ @@ -709,48 +709,49 @@ static int connection_ap_handshake_process_socks(connection_t *conn) { if (rend_parse_rendezvous_address(socks->address) < 0) { /* normal request */ conn->state = AP_CONN_STATE_CIRCUIT_WAIT; - conn->purpose = AP_PURPOSE_GENERAL; - /* attaching to a dirty circuit is fine */ return connection_ap_handshake_attach_circuit(conn); } else { /* it's a hidden-service request */ const char *descp; int desc_len; - strcpy(conn->rend_query, socks->address); + strcpy(conn->rend_query, socks->address); /* this strcpy is safe -RD */ log_fn(LOG_INFO,"Got a hidden service request for ID '%s'", conn->rend_query); /* see if we already have it cached */ if (rend_cache_lookup(conn->rend_query, &descp, &desc_len) == 1) { - conn->purpose = AP_PURPOSE_RENDPOINT_WAIT; + conn->state = AP_CONN_STATE_CIRCUIT_WAIT; return connection_ap_handshake_attach_circuit(conn); - //circuit_launch_new(CIRCUIT_PURPOSE_C_ESTABLISH_REND, NULL); } else { - conn->purpose = AP_PURPOSE_RENDDESC_WAIT; - /* initiate a dir hidserv desc lookup */ - directory_initiate_command(router_pick_directory_server(), - DIR_PURPOSE_FETCH_RENDDESC, - conn->rend_query, strlen(conn->rend_query)); + conn->state = AP_CONN_STATE_RENDDESC_WAIT; + if(!connection_get_by_type_rendquery(CONN_TYPE_DIR, conn->rend_query)) { + /* not one already; initiate a dir rend desc lookup */ + directory_initiate_command(router_pick_directory_server(), + DIR_PURPOSE_FETCH_RENDDESC, + conn->rend_query, strlen(conn->rend_query)); + } return 0; } } return 0; } -/* find an open circ that we're happy with: return 1. if there isn't - * one, launch one and return 0. if it will never work, return -1. - * write the found or launched circ into *circp. +/* Find an open circ that we're happy with: return 1. if there isn't + * one, and there isn't one on the way, launch one and return 0. if it + * will never work, return -1. + * write the found or in-progress or launched circ into *circp. */ static int -get_open_circ_or_launch(connection_t *conn, - uint8_t desired_circuit_purpose, - circuit_t **circp) { +circuit_get_open_circ_or_launch(connection_t *conn, + uint8_t desired_circuit_purpose, + circuit_t **circp) { circuit_t *circ; uint32_t addr; assert(conn); assert(circp); + assert(conn->state == AP_CONN_STATE_CIRCUIT_WAIT); - circ = circuit_get_newest(conn, 1, desired_circuit_purpose); + circ = circuit_get_best(conn, 1, desired_circuit_purpose); if(circ) { *circp = circ; @@ -760,7 +761,7 @@ get_open_circ_or_launch(connection_t *conn, log_fn(LOG_INFO,"No safe circuit (purpose %d) ready for edge connection; delaying.", desired_circuit_purpose); - if(conn->purpose == AP_PURPOSE_GENERAL) { + if(!*conn->rend_query) { /* general purpose circ */ addr = client_dns_lookup_entry(conn->socks_request->address); if(router_exit_policy_all_routers_reject(addr, conn->socks_request->port)) { log_fn(LOG_WARN,"No Tor server exists that allows exit to %s:%d. Rejecting.", @@ -768,13 +769,33 @@ get_open_circ_or_launch(connection_t *conn, return -1; } } - if(!circuit_get_newest(conn, 0, desired_circuit_purpose)) { - /* is one already on the way? */ - circ = circuit_launch_new(desired_circuit_purpose, NULL); - /* depending on purpose, store stuff into circ */ + + /* is one already on the way? */ + circ = circuit_get_best(conn, 0, desired_circuit_purpose); + if(!circ) { + char *exitname=NULL; + uint8_t new_circ_purpose; + + if(desired_circuit_purpose == CIRCUIT_PURPOSE_C_INTRODUCING) { + /* need to pick an intro point */ + exitname = rend_get_random_intro(conn->rend_query); + if(!exitname) { + log_fn(LOG_WARN,"Couldn't get an intro point for '%s'. Closing conn.", + conn->rend_query); + return -1; + } + log_fn(LOG_INFO,"Chose %s as intro point for %s.", exitname, conn->rend_query); + } + + if(desired_circuit_purpose == CIRCUIT_PURPOSE_C_REND_JOINED) + new_circ_purpose = CIRCUIT_PURPOSE_C_ESTABLISH_REND; + else + new_circ_purpose = desired_circuit_purpose; + + circ = circuit_launch_new(new_circ_purpose, exitname); + if(circ && - (desired_circuit_purpose == CIRCUIT_PURPOSE_C_GENERAL || - desired_circuit_purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND)) { + (desired_circuit_purpose != CIRCUIT_PURPOSE_C_GENERAL)) { /* then write the service_id into circ */ strcpy(circ->rend_query, conn->rend_query); } @@ -791,8 +812,6 @@ get_open_circ_or_launch(connection_t *conn, * right next step, and return 1. */ int connection_ap_handshake_attach_circuit(connection_t *conn) { - circuit_t *circ=NULL; - uint8_t desired_circuit_purpose; int retval; assert(conn); @@ -800,60 +819,74 @@ int connection_ap_handshake_attach_circuit(connection_t *conn) { assert(conn->state == AP_CONN_STATE_CIRCUIT_WAIT); assert(conn->socks_request); - if(conn->purpose == AP_PURPOSE_RENDDESC_WAIT) - return 0; /* these guys don't attach to circuits directly */ + if(!*conn->rend_query) { /* we're a general conn */ + circuit_t *circ=NULL; - switch(conn->purpose) { - case AP_PURPOSE_GENERAL: - desired_circuit_purpose = CIRCUIT_PURPOSE_C_GENERAL; - break; - case AP_PURPOSE_RENDPOINT_WAIT: - desired_circuit_purpose = CIRCUIT_PURPOSE_C_ESTABLISH_REND; - break; - case AP_PURPOSE_INTROPOINT_WAIT: - desired_circuit_purpose = CIRCUIT_PURPOSE_C_INTRODUCING; - break; - default: - log_fn(LOG_ERR, "Got unexpected purpose: %d", conn->purpose); - assert(0); /* never reached */ - } + /* find the circuit that we should use, if there is one. */ + retval = circuit_get_open_circ_or_launch(conn, CIRCUIT_PURPOSE_C_GENERAL, &circ); + if(retval < 1) + return retval; - /* find the circuit that we should use, if there is one. */ - retval = get_open_circ_or_launch(conn, desired_circuit_purpose, &circ); - if(retval < 1) - return retval; + /* We have found a suitable circuit for our conn. Hurray. */ - /* We have found a suitable circuit for our conn. Hurray. */ + /* here, print the circ's path. so people can figure out which circs are sucking. */ + circuit_log_path(LOG_INFO,circ); - /* here, print the circ's path. so people can figure out which circs are sucking. */ - circuit_log_path(LOG_INFO,circ); + if(!circ->timestamp_dirty) + circ->timestamp_dirty = time(NULL); - if(!circ->timestamp_dirty) - circ->timestamp_dirty = time(NULL); + /* add it into the linked list of streams on this circuit */ + log_fn(LOG_DEBUG,"attaching new conn to circ. n_circ_id %d.", circ->n_circ_id); + conn->next_stream = circ->p_streams; + /* assert_connection_ok(conn, time(NULL)); */ + circ->p_streams = conn; - switch(conn->purpose) { - case AP_PURPOSE_GENERAL: - /* add it into the linked list of streams on this circuit */ - log_fn(LOG_DEBUG,"attaching new conn to circ. n_circ_id %d.", circ->n_circ_id); - conn->next_stream = circ->p_streams; - /* assert_connection_ok(conn, time(NULL)); */ - circ->p_streams = conn; + assert(circ->cpath && circ->cpath->prev); + assert(circ->cpath->prev->state == CPATH_STATE_OPEN); + conn->cpath_layer = circ->cpath->prev; - assert(circ->cpath && circ->cpath->prev); - assert(circ->cpath->prev->state == CPATH_STATE_OPEN); - conn->cpath_layer = circ->cpath->prev; + connection_ap_handshake_send_begin(conn, circ); - connection_ap_handshake_send_begin(conn, circ); - break; - case AP_PURPOSE_RENDPOINT_WAIT: - rend_client_rendcirc_is_ready(conn, circ); - break; - case AP_PURPOSE_INTROPOINT_WAIT: - rend_client_introcirc_is_ready(conn, circ); - break; - } + return 1; + + } else { /* we're a rendezvous conn */ + circuit_t *rendcirc=NULL, *introcirc=NULL; + + /* first, find a rendezvous circuit for us */ + + retval = circuit_get_open_circ_or_launch(conn, CIRCUIT_PURPOSE_C_REND_JOINED, &rendcirc); + if(retval < 0) return -1; /* failed */ + + if(retval > 0) { + /* one is already established, attach */ + + log_fn(LOG_WARN,"XXX rend joined circ already here. should reuse."); + return -1; + } - return 1; + if(rendcirc && + rendcirc->purpose == CIRCUIT_PURPOSE_C_REND_READY && + rendcirc->build_state->pending_final_cpath) { + log_fn(LOG_WARN,"XXX pending-join circ already here. should reuse."); + return -1; + } + + /* it's on its way. find an intro circ. */ + retval = circuit_get_open_circ_or_launch(conn, CIRCUIT_PURPOSE_C_INTRODUCING, &introcirc); + if(retval < 0) return -1; /* failed */ + + if(retval > 0) { + log_fn(LOG_INFO,"Intro circ is ready for us"); + if(rendcirc && + rendcirc->purpose == CIRCUIT_PURPOSE_C_REND_READY) { + /* then we know !pending_final_cpath, from above */ + log_fn(LOG_WARN,"XXX intro and rend are both ready. do the magic."); + return -1; + } + } + log_fn(LOG_INFO,"Intro and rend circs are not both ready. Stalling conn."); + return 0; + } } /* Iterate over the two bytes of stream_id until we get one that is not @@ -961,7 +994,6 @@ int connection_ap_make_bridge(char *address, uint16_t port) { } conn->state = AP_CONN_STATE_CIRCUIT_WAIT; - conn->purpose = AP_PURPOSE_GENERAL; connection_start_reading(conn); /* attaching to a dirty circuit is fine */ |