mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-20 10:12:15 +01:00
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
This commit is contained in:
parent
a9813f0210
commit
7793078dff
128
src/or/circuit.c
128
src/or/circuit.c
@ -13,7 +13,7 @@ static void circuit_free_cpath_node(crypt_path_t *victim);
|
||||
static uint16_t get_unique_circ_id_by_conn(connection_t *conn, int circ_id_type);
|
||||
static void circuit_rep_hist_note_result(circuit_t *circ);
|
||||
|
||||
static void circuit_is_ready(circuit_t *circ);
|
||||
static void circuit_is_open(circuit_t *circ);
|
||||
static void circuit_failed(circuit_t *circ);
|
||||
static circuit_t *circuit_establish_circuit(uint8_t purpose, const char *exit_nickname);
|
||||
|
||||
@ -250,21 +250,30 @@ circuit_t *circuit_get_by_conn(connection_t *conn) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find the newest circ that conn can use, preferably one which is
|
||||
/* Dear god this function needs refactoring. */
|
||||
/* Find the best circ that conn can use, preferably one which is
|
||||
* dirty. Circ must not be too old.
|
||||
* If !conn, return newest.
|
||||
*
|
||||
* If must_be_open, ignore circs not in CIRCUIT_STATE_OPEN.
|
||||
*
|
||||
* circ_purpose specifies what sort of circuit we must have.
|
||||
* It can be C_GENERAL, C_INTRODUCING, or C_REND_JOINED.
|
||||
*
|
||||
* If it's REND_JOINED and must_be_open==0, then return the closest
|
||||
* rendezvous-purposed circuit that you can find.
|
||||
*
|
||||
* If circ_purpose is not GENERAL, then conn must be defined.
|
||||
* If circ_purpose is C_ESTABLISH_REND, then it's also ok
|
||||
* to return a C_REND_JOINED circ.
|
||||
*/
|
||||
circuit_t *circuit_get_newest(connection_t *conn,
|
||||
int must_be_open, uint8_t circ_purpose) {
|
||||
circuit_t *circ, *newest=NULL, *leastdirty=NULL;
|
||||
circuit_t *circuit_get_best(connection_t *conn,
|
||||
int must_be_open, uint8_t purpose) {
|
||||
circuit_t *circ, *best=NULL;
|
||||
routerinfo_t *exitrouter;
|
||||
time_t now = time(NULL);
|
||||
|
||||
assert(purpose == CIRCUIT_PURPOSE_C_GENERAL ||
|
||||
purpose == CIRCUIT_PURPOSE_C_INTRODUCING ||
|
||||
purpose == CIRCUIT_PURPOSE_C_REND_JOINED);
|
||||
|
||||
for (circ=global_circuitlist;circ;circ = circ->next) {
|
||||
if (!circ->cpath)
|
||||
@ -274,18 +283,23 @@ circuit_t *circuit_get_newest(connection_t *conn,
|
||||
if (circ->marked_for_close)
|
||||
continue;
|
||||
|
||||
/* if this isn't our purpose, skip. except, if our purpose is
|
||||
* establish_rend, keep going if circ is rend_joined.
|
||||
*/
|
||||
if (circ->purpose != circ_purpose &&
|
||||
(circ_purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND ||
|
||||
circ->purpose != CIRCUIT_PURPOSE_C_REND_JOINED))
|
||||
/* if this circ isn't our purpose, skip. */
|
||||
if(purpose == CIRCUIT_PURPOSE_C_REND_JOINED) {
|
||||
if(must_be_open && purpose != circ->purpose)
|
||||
continue;
|
||||
if(circ->purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND &&
|
||||
circ->purpose != CIRCUIT_PURPOSE_C_REND_READY &&
|
||||
circ->purpose != CIRCUIT_PURPOSE_C_REND_JOINED)
|
||||
continue;
|
||||
} else {
|
||||
if(purpose != circ->purpose)
|
||||
continue;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (must_be_clean && circ->timestamp_dirty)
|
||||
continue; /* ignore dirty circs */
|
||||
#endif
|
||||
if(purpose == CIRCUIT_PURPOSE_C_GENERAL)
|
||||
if(circ->timestamp_dirty &&
|
||||
circ->timestamp_dirty+options.NewCircuitPeriod < now)
|
||||
continue; /* too old */
|
||||
|
||||
if(conn) {
|
||||
/* decide if this circ is suitable for this conn */
|
||||
@ -296,10 +310,12 @@ circuit_t *circuit_get_newest(connection_t *conn,
|
||||
else /* not open */
|
||||
exitrouter = router_get_by_nickname(circ->build_state->chosen_exit);
|
||||
|
||||
if(!exitrouter)
|
||||
if(!exitrouter) {
|
||||
log_fn(LOG_INFO,"Skipping broken circ (exit router vanished)");
|
||||
continue; /* this circuit is screwed and doesn't know it yet */
|
||||
}
|
||||
|
||||
if(circ_purpose == CIRCUIT_PURPOSE_C_GENERAL) {
|
||||
if(purpose == CIRCUIT_PURPOSE_C_GENERAL) {
|
||||
if(connection_ap_can_use_exit(conn, exitrouter) == ADDR_POLICY_REJECTED) {
|
||||
/* can't exit from this router */
|
||||
continue;
|
||||
@ -312,27 +328,40 @@ circuit_t *circuit_get_newest(connection_t *conn,
|
||||
}
|
||||
}
|
||||
|
||||
if(!newest || newest->timestamp_created < circ->timestamp_created) {
|
||||
newest = circ;
|
||||
/* now this is an acceptable circ to hand back. but that doesn't
|
||||
* mean it's the *best* circ to hand back. try to decide.
|
||||
*/
|
||||
if(!best)
|
||||
best = circ;
|
||||
switch(purpose) {
|
||||
case CIRCUIT_PURPOSE_C_GENERAL:
|
||||
/* if it's used but less dirty it's best;
|
||||
* else if it's more recently created it's best
|
||||
*/
|
||||
if(best->timestamp_dirty) {
|
||||
if(circ->timestamp_dirty &&
|
||||
circ->timestamp_dirty > best->timestamp_dirty)
|
||||
best = circ;
|
||||
} else {
|
||||
if(circ->timestamp_dirty ||
|
||||
circ->timestamp_created > best->timestamp_created)
|
||||
best = circ;
|
||||
}
|
||||
if(conn && circ->timestamp_dirty &&
|
||||
(!leastdirty || leastdirty->timestamp_dirty < circ->timestamp_dirty)) {
|
||||
leastdirty = circ;
|
||||
break;
|
||||
case CIRCUIT_PURPOSE_C_INTRODUCING:
|
||||
/* more recently created is best */
|
||||
if(circ->timestamp_created > best->timestamp_created)
|
||||
best = circ;
|
||||
break;
|
||||
case CIRCUIT_PURPOSE_C_REND_JOINED:
|
||||
/* the closer it is to rend_joined the better it is */
|
||||
if(circ->purpose > best->purpose)
|
||||
best = circ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(leastdirty &&
|
||||
leastdirty->timestamp_dirty+options.NewCircuitPeriod > time(NULL)) {
|
||||
/* log_fn(LOG_DEBUG,"Choosing in-use circuit %s:%d:%d.",
|
||||
leastdirty->n_conn->address, leastdirty->n_port, leastdirty->n_circ_id); */
|
||||
return leastdirty;
|
||||
}
|
||||
if(newest) {
|
||||
/* log_fn(LOG_DEBUG,"Choosing circuit %s:%d:%d.",
|
||||
newest->n_conn->address, newest->n_port, newest->n_circ_id); */
|
||||
return newest;
|
||||
}
|
||||
return NULL;
|
||||
return best;
|
||||
}
|
||||
|
||||
/* Return the first circuit in global_circuitlist after 'start' whose
|
||||
@ -422,8 +451,9 @@ int circuit_count_building(void) {
|
||||
}
|
||||
|
||||
#define MIN_CIRCUITS_HANDLING_STREAM 2
|
||||
/* return 1 if at least MIN_CIRCUITS_HANDLING_STREAM non-open circuits
|
||||
* will have an acceptable exit node for conn. Else return 0.
|
||||
/* return 1 if at least MIN_CIRCUITS_HANDLING_STREAM non-open
|
||||
* general-purpose circuits will have an acceptable exit node for
|
||||
* conn. Else return 0.
|
||||
*/
|
||||
int circuit_stream_is_being_handled(connection_t *conn) {
|
||||
circuit_t *circ;
|
||||
@ -432,7 +462,7 @@ int circuit_stream_is_being_handled(connection_t *conn) {
|
||||
|
||||
for(circ=global_circuitlist;circ;circ = circ->next) {
|
||||
if(circ->cpath && circ->state != CIRCUIT_STATE_OPEN &&
|
||||
!circ->marked_for_close) {
|
||||
!circ->marked_for_close && circ->purpose == CIRCUIT_PURPOSE_C_GENERAL) {
|
||||
exitrouter = router_get_by_nickname(circ->build_state->chosen_exit);
|
||||
if(exitrouter && connection_ap_can_use_exit(conn, exitrouter) != ADDR_POLICY_REJECTED)
|
||||
if(++num >= MIN_CIRCUITS_HANDLING_STREAM)
|
||||
@ -1047,24 +1077,20 @@ void circuit_expire_unused_circuits(void) {
|
||||
smartlist_free(unused_open_circs);
|
||||
}
|
||||
|
||||
static void circuit_is_ready(circuit_t *circ) {
|
||||
static void circuit_is_open(circuit_t *circ) {
|
||||
|
||||
/* should maybe break this into rend_circuit_is_ready() one day */
|
||||
switch(circ->purpose) {
|
||||
case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
|
||||
rend_client_rendcirc_is_open(circ);
|
||||
break;
|
||||
case CIRCUIT_PURPOSE_C_INTRODUCING:
|
||||
rend_client_introcirc_is_open(circ);
|
||||
break;
|
||||
case CIRCUIT_PURPOSE_C_GENERAL:
|
||||
/* Tell any AP connections that have been waiting for a new
|
||||
* circuit that one is ready. */
|
||||
connection_ap_attach_pending();
|
||||
break;
|
||||
case CIRCUIT_PURPOSE_C_INTRODUCING:
|
||||
/* at Alice, connecting to intro point */
|
||||
connection_ap_attach_pending();
|
||||
break;
|
||||
case CIRCUIT_PURPOSE_C_ESTABLISH_REND:
|
||||
/* at Alice, waiting for Bob */
|
||||
/* XXXNM make and send the rendezvous cookie, and store it in circ */
|
||||
connection_ap_attach_pending();
|
||||
break;
|
||||
case CIRCUIT_PURPOSE_S_ESTABLISH_INTRO:
|
||||
/* at Bob, waiting for introductions */
|
||||
rend_service_intro_is_ready(circ);
|
||||
@ -1278,7 +1304,7 @@ int circuit_send_next_onion_skin(circuit_t *circ) {
|
||||
log_fn(LOG_NOTICE,"Tor has successfully opened a circuit. Looks like it's working.");
|
||||
}
|
||||
circuit_rep_hist_note_result(circ);
|
||||
circuit_is_ready(circ); /* do other actions as necessary */
|
||||
circuit_is_open(circ); /* do other actions as necessary */
|
||||
return 0;
|
||||
} else if (r<0) {
|
||||
log_fn(LOG_INFO,"Unable to extend circuit path.");
|
||||
|
@ -596,11 +596,18 @@ int getconfig(int argc, char **argv, or_options_t *options) {
|
||||
if (options->Nickname == NULL) {
|
||||
log_fn(LOG_WARN,"Nickname required if ORPort is set, but not found.");
|
||||
result = -1;
|
||||
} else if (strspn(options->Nickname, LEGAL_NICKNAME_CHARACTERS) !=
|
||||
} else {
|
||||
if (strspn(options->Nickname, LEGAL_NICKNAME_CHARACTERS) !=
|
||||
strlen(options->Nickname)) {
|
||||
log_fn(LOG_WARN, "Nickname '%s' contains illegal characters.", options->Nickname);
|
||||
result = -1;
|
||||
}
|
||||
if (strlen(options->Nickname) > MAX_NICKNAME_LEN) {
|
||||
log_fn(LOG_WARN, "Nickname '%s' has more than %d characters.",
|
||||
options->Nickname, MAX_NICKNAME_LEN);
|
||||
result = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(options->ORPort) { /* get an IP for ourselves */
|
||||
@ -654,6 +661,10 @@ int getconfig(int argc, char **argv, or_options_t *options) {
|
||||
result = -1;
|
||||
}
|
||||
|
||||
/* XXX look at the various nicknamelists and make sure they're
|
||||
* valid and don't have hostnames that are too long.
|
||||
*/
|
||||
|
||||
if (rend_config_services(options) < 0) {
|
||||
result = -1;
|
||||
}
|
||||
|
@ -866,6 +866,22 @@ connection_t *connection_get_by_type_state_lastwritten(int type, int state) {
|
||||
return best;
|
||||
}
|
||||
|
||||
connection_t *connection_get_by_type_rendquery(int type, char *rendquery) {
|
||||
int i, n;
|
||||
connection_t *conn;
|
||||
connection_t **carray;
|
||||
|
||||
get_connection_array(&carray,&n);
|
||||
for(i=0;i<n;i++) {
|
||||
conn = carray[i];
|
||||
if(conn->type == type &&
|
||||
!conn->marked_for_close &&
|
||||
!rend_cmp_service_ids(rendquery, conn->rend_query))
|
||||
return conn;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int connection_is_listener(connection_t *conn) {
|
||||
if(conn->type == CONN_TYPE_OR_LISTENER ||
|
||||
conn->type == CONN_TYPE_AP_LISTENER ||
|
||||
@ -1026,9 +1042,8 @@ void assert_connection_ok(connection_t *conn, time_t now)
|
||||
} else {
|
||||
assert(!conn->socks_request);
|
||||
}
|
||||
if(conn->type != CONN_TYPE_DIR &&
|
||||
conn->type != CONN_TYPE_AP) {
|
||||
assert(!conn->purpose); /* only used for dir and ap types currently */
|
||||
if(conn->type != CONN_TYPE_DIR) {
|
||||
assert(!conn->purpose); /* only used for dir types currently */
|
||||
}
|
||||
|
||||
switch(conn->type)
|
||||
|
@ -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,39 +709,39 @@ 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 */
|
||||
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,
|
||||
circuit_get_open_circ_or_launch(connection_t *conn,
|
||||
uint8_t desired_circuit_purpose,
|
||||
circuit_t **circp) {
|
||||
circuit_t *circ;
|
||||
@ -749,8 +749,9 @@ get_open_circ_or_launch(connection_t *conn,
|
||||
|
||||
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 */
|
||||
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,26 +819,11 @@ 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 */
|
||||
|
||||
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 */
|
||||
}
|
||||
if(!*conn->rend_query) { /* we're a general conn */
|
||||
circuit_t *circ=NULL;
|
||||
|
||||
/* find the circuit that we should use, if there is one. */
|
||||
retval = get_open_circ_or_launch(conn, desired_circuit_purpose, &circ);
|
||||
retval = circuit_get_open_circ_or_launch(conn, CIRCUIT_PURPOSE_C_GENERAL, &circ);
|
||||
if(retval < 1)
|
||||
return retval;
|
||||
|
||||
@ -831,8 +835,6 @@ int connection_ap_handshake_attach_circuit(connection_t *conn) {
|
||||
if(!circ->timestamp_dirty)
|
||||
circ->timestamp_dirty = time(NULL);
|
||||
|
||||
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;
|
||||
@ -844,16 +846,47 @@ int connection_ap_handshake_attach_circuit(connection_t *conn) {
|
||||
conn->cpath_layer = circ->cpath->prev;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 */
|
||||
|
@ -206,7 +206,7 @@ dirserv_add_descriptor(const char **desc)
|
||||
|
||||
start = strstr(*desc, "router ");
|
||||
if (!start) {
|
||||
log(LOG_WARN, "no descriptor found.");
|
||||
log_fn(LOG_WARN, "no 'router' line found. This is not a descriptor.");
|
||||
return -1;
|
||||
}
|
||||
if ((end = strstr(start+6, "\nrouter "))) {
|
||||
|
@ -384,7 +384,7 @@ static void run_scheduled_events(time_t now) {
|
||||
/* Build a new test circuit every 5 minutes */
|
||||
#define TESTING_CIRCUIT_INTERVAL 300
|
||||
|
||||
circ = circuit_get_newest(NULL, 1, CIRCUIT_PURPOSE_C_GENERAL);
|
||||
circ = circuit_get_best(NULL, 1, CIRCUIT_PURPOSE_C_GENERAL);
|
||||
if(time_to_new_circuit < now) {
|
||||
client_dns_clean();
|
||||
circuit_expire_unused_circuits();
|
||||
|
65
src/or/or.h
65
src/or/or.h
@ -100,7 +100,7 @@
|
||||
can be lowered by config file */
|
||||
|
||||
#define DEFAULT_BANDWIDTH_OP (1024 * 1000)
|
||||
#define MAX_NICKNAME_LEN 32
|
||||
#define MAX_NICKNAME_LEN 19
|
||||
#define MAX_DIR_SIZE 500000
|
||||
|
||||
#ifdef TOR_PERF
|
||||
@ -159,18 +159,11 @@
|
||||
/* the AP state values must be disjoint from the EXIT state values */
|
||||
#define _AP_CONN_STATE_MIN 5
|
||||
#define AP_CONN_STATE_SOCKS_WAIT 5
|
||||
#define AP_CONN_STATE_CIRCUIT_WAIT 6
|
||||
#define AP_CONN_STATE_CONNECT_WAIT 7
|
||||
#define AP_CONN_STATE_OPEN 8
|
||||
#define _AP_CONN_STATE_MAX 8
|
||||
|
||||
/* only used if state==CIRCUIT_WAIT */
|
||||
#define _AP_PURPOSE_MIN 1
|
||||
#define AP_PURPOSE_GENERAL 1
|
||||
#define AP_PURPOSE_RENDDESC_WAIT 2
|
||||
#define AP_PURPOSE_RENDPOINT_WAIT 3
|
||||
#define AP_PURPOSE_INTROPOINT_WAIT 4
|
||||
#define _AP_PURPOSE_MAX 4
|
||||
#define AP_CONN_STATE_RENDDESC_WAIT 6
|
||||
#define AP_CONN_STATE_CIRCUIT_WAIT 7
|
||||
#define AP_CONN_STATE_CONNECT_WAIT 8
|
||||
#define AP_CONN_STATE_OPEN 9
|
||||
#define _AP_CONN_STATE_MAX 9
|
||||
|
||||
#define _DIR_CONN_STATE_MIN 1
|
||||
#define DIR_CONN_STATE_CONNECTING 1
|
||||
@ -194,23 +187,42 @@
|
||||
#define CIRCUIT_STATE_OPEN 3 /* onionskin(s) processed, ready to send/receive cells */
|
||||
|
||||
#define _CIRCUIT_PURPOSE_MIN 1
|
||||
|
||||
/* these circuits were initiated elsewhere */
|
||||
#define CIRCUIT_PURPOSE_OR 1 /* normal circuit, at OR. */
|
||||
#define CIRCUIT_PURPOSE_INTRO_POINT 2 /* At OR, from Bob, waiting for intro from Alices */
|
||||
#define CIRCUIT_PURPOSE_REND_POINT_WAITING 3 /* At OR, from Alice, waiting for Bob */
|
||||
#define CIRCUIT_PURPOSE_REND_ESTABLISHED 4 /* At OR, both circuits have this purpose */
|
||||
|
||||
/* these circuits originate at this node */
|
||||
|
||||
/* here's how circ client-side purposes work:
|
||||
* normal circuits are C_GENERAL.
|
||||
* circuits that are c_introducing are either on their way to
|
||||
* becoming open, or they are open but haven't been used yet.
|
||||
* (as soon as they are used, they are destroyed.)
|
||||
* circuits that are c_establish_rend are either on their way
|
||||
* to becoming open, or they are open and have sent the
|
||||
* establish_rendezvous cell but haven't received an ack.
|
||||
* circuits that are c_rend_ready are open and have received an
|
||||
* ack, but haven't heard from bob yet. if they have a
|
||||
* buildstate->pending_final_cpath then they're expecting a
|
||||
* cell from bob, else they're not.
|
||||
* circuits that are c_rend_joined are open, have heard from
|
||||
* bob, and are talking to him.
|
||||
*/
|
||||
#define CIRCUIT_PURPOSE_C_GENERAL 5 /* normal circuit, with cpath */
|
||||
#define CIRCUIT_PURPOSE_C_INTRODUCING 6 /* at Alice, connecting to intro point */
|
||||
#define CIRCUIT_PURPOSE_C_ESTABLISH_REND 7 /* at Alice, waiting for Bob */
|
||||
#define CIRCUIT_PURPOSE_C_REND_JOINED 8 /* at Alice, rendezvous established.*/
|
||||
#define CIRCUIT_PURPOSE_C_ESTABLISH_REND 7 /* at Alice, waiting for ack */
|
||||
#define CIRCUIT_PURPOSE_C_REND_READY 8 /* at Alice, waiting for Bob */
|
||||
#define CIRCUIT_PURPOSE_C_REND_JOINED 9 /* at Alice, rendezvous established */
|
||||
|
||||
#define CIRCUIT_PURPOSE_S_ESTABLISH_INTRO 9 /* at Bob, waiting for introductions */
|
||||
#define CIRCUIT_PURPOSE_S_INTRO 10 /* at Bob, successfully established intro */
|
||||
#define CIRCUIT_PURPOSE_S_CONNECT_REND 11 /* at Bob, connecting to rend point */
|
||||
#define CIRCUIT_PURPOSE_S_ESTABLISH_INTRO 10 /* at Bob, waiting for introductions */
|
||||
#define CIRCUIT_PURPOSE_S_INTRO 11 /* at Bob, successfully established intro */
|
||||
#define CIRCUIT_PURPOSE_S_CONNECT_REND 12 /* at Bob, connecting to rend point */
|
||||
|
||||
#define CIRCUIT_PURPOSE_S_REND_JOINED 12 /* at Bob, rendezvous established.*/
|
||||
#define _CIRCUIT_PURPOSE_MAX 11
|
||||
#define CIRCUIT_PURPOSE_S_REND_JOINED 13 /* at Bob, rendezvous established.*/
|
||||
#define _CIRCUIT_PURPOSE_MAX 13
|
||||
|
||||
#define RELAY_COMMAND_BEGIN 1
|
||||
#define RELAY_COMMAND_DATA 2
|
||||
@ -347,7 +359,7 @@ struct connection_t {
|
||||
|
||||
uint8_t type;
|
||||
uint8_t state;
|
||||
uint8_t purpose; /* only used for DIR and AP types currently */
|
||||
uint8_t purpose; /* only used for DIR types currently */
|
||||
uint8_t wants_to_read; /* should we start reading again once
|
||||
* the bandwidth throttler allows it?
|
||||
*/
|
||||
@ -687,8 +699,8 @@ int _circuit_mark_for_close(circuit_t *circ);
|
||||
|
||||
circuit_t *circuit_get_by_circ_id_conn(uint16_t circ_id, connection_t *conn);
|
||||
circuit_t *circuit_get_by_conn(connection_t *conn);
|
||||
circuit_t *circuit_get_newest(connection_t *conn,
|
||||
int must_be_open, uint8_t conn_purpose);
|
||||
circuit_t *circuit_get_best(connection_t *conn,
|
||||
int must_be_open, uint8_t purpose);
|
||||
circuit_t *circuit_get_next_by_pk_and_purpose(circuit_t *circuit,
|
||||
const char *servid, uint8_t purpose);
|
||||
circuit_t *circuit_get_rendezvous(const char *cookie);
|
||||
@ -803,6 +815,7 @@ connection_t *connection_exact_get_by_addr_port(uint32_t addr, uint16_t port);
|
||||
connection_t *connection_get_by_type(int type);
|
||||
connection_t *connection_get_by_type_state(int type, int state);
|
||||
connection_t *connection_get_by_type_state_lastwritten(int type, int state);
|
||||
connection_t *connection_get_by_type_rendquery(int type, char *rendquery);
|
||||
|
||||
#define connection_speaks_cells(conn) ((conn)->type == CONN_TYPE_OR)
|
||||
#define connection_has_pending_tls_data(conn) \
|
||||
@ -1025,12 +1038,14 @@ void rep_hist_dump_stats(time_t now, int severity);
|
||||
|
||||
/********************************* rendclient.c ***************************/
|
||||
|
||||
void rend_client_introcirc_is_ready(connection_t *apconn, circuit_t *circ);
|
||||
void rend_client_rendcirc_is_ready(connection_t *apconn, circuit_t *circ);
|
||||
void rend_client_introcirc_is_open(circuit_t *circ);
|
||||
void rend_client_rendcirc_is_open(circuit_t *circ);
|
||||
int rend_client_rendezvous_acked(circuit_t *circ, const char *request, int request_len);
|
||||
void rend_client_rendezvous(connection_t *apconn, circuit_t *circ);
|
||||
void rend_client_desc_fetched(char *query, int success);
|
||||
|
||||
int rend_cmp_service_ids(char *one, char *two);
|
||||
char *rend_get_random_intro(char *query);
|
||||
int rend_parse_rendezvous_address(char *address);
|
||||
|
||||
int rend_client_send_establish_rendezvous(circuit_t *circ);
|
||||
|
@ -6,10 +6,13 @@
|
||||
|
||||
/* send the introduce cell */
|
||||
void
|
||||
rend_client_introcirc_is_ready(connection_t *apconn, circuit_t *circ)
|
||||
rend_client_introcirc_is_open(circuit_t *circ)
|
||||
{
|
||||
assert(circ->purpose == CIRCUIT_PURPOSE_C_INTRODUCING);
|
||||
assert(circ->cpath);
|
||||
|
||||
log_fn(LOG_WARN,"introcirc is ready");
|
||||
log_fn(LOG_INFO,"introcirc is open");
|
||||
connection_ap_attach_pending();
|
||||
}
|
||||
|
||||
int
|
||||
@ -35,24 +38,33 @@ rend_client_send_establish_rendezvous(circuit_t *circ)
|
||||
|
||||
/* send the rendezvous cell */
|
||||
void
|
||||
rend_client_rendcirc_is_ready(connection_t *apconn, circuit_t *circ)
|
||||
rend_client_rendcirc_is_open(circuit_t *circ)
|
||||
{
|
||||
circuit_t *introcirc;
|
||||
|
||||
assert(apconn->purpose == AP_PURPOSE_RENDPOINT_WAIT);
|
||||
assert(circ->purpose == CIRCUIT_PURPOSE_C_ESTABLISH_REND);
|
||||
assert(circ->cpath);
|
||||
|
||||
log_fn(LOG_INFO,"rendcirc is ready");
|
||||
log_fn(LOG_INFO,"rendcirc is open");
|
||||
|
||||
/* XXX generate a rendezvous cookie, store it in circ */
|
||||
/* store rendcirc in apconn */
|
||||
|
||||
apconn->purpose = AP_PURPOSE_INTROPOINT_WAIT;
|
||||
if (connection_ap_handshake_attach_circuit(apconn) < 0) {
|
||||
log_fn(LOG_WARN,"failed to start intro point. Closing conn.");
|
||||
connection_mark_for_close(apconn,0);
|
||||
/* generate a rendezvous cookie, store it in circ */
|
||||
if (rend_client_send_establish_rendezvous(circ) < 0) {
|
||||
circuit_mark_for_close(circ);
|
||||
return;
|
||||
}
|
||||
|
||||
connection_ap_attach_pending();
|
||||
}
|
||||
|
||||
int
|
||||
rend_client_rendezvous_acked(circuit_t *circ, const char *request, int request_len)
|
||||
{
|
||||
/* we just got an ack for our establish-rendezvous. switch purposes. */
|
||||
if(circ->purpose != CIRCUIT_PURPOSE_C_ESTABLISH_REND) {
|
||||
log_fn(LOG_WARN,"Got a rendezvous ack when we weren't expecting one. Closing circ.");
|
||||
circuit_mark_for_close(circ);
|
||||
return -1;
|
||||
}
|
||||
circ->purpose = CIRCUIT_PURPOSE_C_REND_READY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* bob sent us a rendezvous cell, join the circs. */
|
||||
@ -80,16 +92,14 @@ void rend_client_desc_fetched(char *query, int success) {
|
||||
for (i = 0; i < n; ++i) {
|
||||
conn = carray[i];
|
||||
if (conn->type != CONN_TYPE_AP ||
|
||||
conn->state != AP_CONN_STATE_CIRCUIT_WAIT)
|
||||
continue;
|
||||
if (conn->purpose != AP_PURPOSE_RENDDESC_WAIT)
|
||||
conn->state != AP_CONN_STATE_RENDDESC_WAIT)
|
||||
continue;
|
||||
if (rend_cmp_service_ids(conn->rend_query, query))
|
||||
continue;
|
||||
/* great, this guy was waiting */
|
||||
if(success) {
|
||||
log_fn(LOG_INFO,"Rend desc retrieved. Launching rend circ.");
|
||||
conn->purpose = AP_PURPOSE_RENDPOINT_WAIT;
|
||||
log_fn(LOG_INFO,"Rend desc retrieved. Launching circuits.");
|
||||
conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
|
||||
if (connection_ap_handshake_attach_circuit(conn) < 0) {
|
||||
/* it will never work */
|
||||
log_fn(LOG_WARN,"attaching to a rend circ failed. Closing conn.");
|
||||
@ -106,6 +116,40 @@ int rend_cmp_service_ids(char *one, char *two) {
|
||||
return strcasecmp(one,two);
|
||||
}
|
||||
|
||||
/* return a pointer to a nickname for a random introduction
|
||||
* point of query. return NULL if error.
|
||||
*/
|
||||
char *rend_get_random_intro(char *query) {
|
||||
const char *descp;
|
||||
int desc_len;
|
||||
int i;
|
||||
smartlist_t *sl;
|
||||
rend_service_descriptor_t *parsed;
|
||||
char *choice;
|
||||
|
||||
if(rend_cache_lookup(query, &descp, &desc_len) < 1) {
|
||||
log_fn(LOG_WARN,"query '%s' didn't have valid rend desc in cache. Failing.", query);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
parsed = rend_parse_service_descriptor(descp,desc_len);
|
||||
if (!parsed) {
|
||||
log_fn(LOG_WARN,"Couldn't parse service descriptor");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sl = smartlist_create();
|
||||
|
||||
/* add the intro point nicknames */
|
||||
for(i=0;i<parsed->n_intro_points;i++)
|
||||
smartlist_add(sl,parsed->intro_points[i]);
|
||||
|
||||
choice = smartlist_choose(sl);
|
||||
smartlist_free(sl);
|
||||
rend_service_descriptor_free(parsed);
|
||||
return choice;
|
||||
}
|
||||
|
||||
/* If address is of the form "y.onion" with a well-formed handle y,
|
||||
* then put a '\0' after y, lower-case it, and return 0.
|
||||
* Else return -1 and change nothing.
|
||||
|
@ -61,6 +61,8 @@ rend_encode_service_descriptor(rend_service_descriptor_t *desc,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* malloc a service_descriptor_t and return it.
|
||||
* return NULL if invalid descriptor or error */
|
||||
rend_service_descriptor_t *rend_parse_service_descriptor(
|
||||
const char *str, int len)
|
||||
{
|
||||
@ -83,6 +85,10 @@ rend_service_descriptor_t *rend_parse_service_descriptor(
|
||||
cp += 4;
|
||||
if (end-cp < 2) goto truncated;
|
||||
result->n_intro_points = get_uint16(cp);
|
||||
if(result->n_intro_points < 1) {
|
||||
log_fn(LOG_WARN,"Service descriptor listed no intro points.");
|
||||
goto error;
|
||||
}
|
||||
result->intro_points = tor_malloc_zero(sizeof(char*)*result->n_intro_points);
|
||||
cp += 2;
|
||||
for (i=0;i<result->n_intro_points;++i) {
|
||||
@ -282,8 +288,7 @@ void rend_process_relay_cell(circuit_t *circ, int command, int length,
|
||||
r = rend_service_intro_established(circ,payload,length);
|
||||
break;
|
||||
case RELAY_COMMAND_RENDEZVOUS_ESTABLISHED:
|
||||
/* r = rend_client_rendezvous_established(circ,payload,length); */
|
||||
log_fn(LOG_NOTICE, "Ignoring a rendezvous_established cell");
|
||||
r = rend_client_rendezvous_acked(circ,payload,length);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
|
@ -193,7 +193,7 @@ static routerinfo_t *router_pick_directory_server_impl(void) {
|
||||
|
||||
void add_nickname_list_to_smartlist(smartlist_t *sl, char *list) {
|
||||
char *start,*end;
|
||||
char nick[MAX_NICKNAME_LEN];
|
||||
char nick[MAX_NICKNAME_LEN+1];
|
||||
routerinfo_t *router;
|
||||
|
||||
assert(sl);
|
||||
|
Loading…
Reference in New Issue
Block a user