mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-24 20:33:31 +01:00
Handle unavailable hidden services better. We try each intro point
until none are left, then we try to refetch the descriptor. If it's the same one we had before, then close streams right then. Whenever a new stream arrives, even if it's right after, optimistically try refetching the descriptor, just in case. svn:r3379
This commit is contained in:
parent
ff48179372
commit
38be533c69
@ -817,18 +817,22 @@ circuit_get_open_circ_or_launch(connection_t *conn,
|
|||||||
|
|
||||||
if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
|
if (desired_circuit_purpose == CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT) {
|
||||||
/* need to pick an intro point */
|
/* need to pick an intro point */
|
||||||
|
try_an_intro_point:
|
||||||
exitname = rend_client_get_random_intro(conn->rend_query);
|
exitname = rend_client_get_random_intro(conn->rend_query);
|
||||||
if (!exitname) {
|
if (!exitname) {
|
||||||
log_fn(LOG_WARN,"Couldn't get an intro point for '%s'. Closing.",
|
log_fn(LOG_INFO,"No intro points for '%s': refetching service descriptor.",
|
||||||
conn->rend_query);
|
conn->rend_query);
|
||||||
return -1;
|
rend_client_refetch_renddesc(conn->rend_query);
|
||||||
|
conn->state = AP_CONN_STATE_RENDDESC_WAIT;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
if (!router_get_by_nickname(exitname)) {
|
if (!router_get_by_nickname(exitname)) {
|
||||||
log_fn(LOG_WARN,"Advertised intro point '%s' is not known. Closing.", exitname);
|
log_fn(LOG_NOTICE,"Advertised intro point '%s' is not recognized for '%s'. Skipping over.",
|
||||||
|
exitname, conn->rend_query);
|
||||||
|
rend_client_remove_intro_point(exitname, conn->rend_query);
|
||||||
tor_free(exitname);
|
tor_free(exitname);
|
||||||
return -1;
|
goto try_an_intro_point;
|
||||||
}
|
}
|
||||||
/* XXX if we failed, then refetch the descriptor */
|
|
||||||
log_fn(LOG_INFO,"Chose %s as intro point for %s.", exitname, conn->rend_query);
|
log_fn(LOG_INFO,"Chose %s as intro point for %s.", exitname, conn->rend_query);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -839,7 +843,7 @@ circuit_get_open_circ_or_launch(connection_t *conn,
|
|||||||
if (conn->chosen_exit_name) {
|
if (conn->chosen_exit_name) {
|
||||||
exitname = tor_strdup(conn->chosen_exit_name);
|
exitname = tor_strdup(conn->chosen_exit_name);
|
||||||
if (!router_get_by_nickname(exitname)) {
|
if (!router_get_by_nickname(exitname)) {
|
||||||
log_fn(LOG_WARN,"Requested exit point '%s' is not known. Closing.", exitname);
|
log_fn(LOG_NOTICE,"Requested exit point '%s' is not known. Closing.", exitname);
|
||||||
tor_free(exitname);
|
tor_free(exitname);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -219,7 +219,7 @@ void connection_about_to_close_connection(connection_t *conn)
|
|||||||
connection_dir_connect_failed(conn);
|
connection_dir_connect_failed(conn);
|
||||||
}
|
}
|
||||||
if (conn->purpose == DIR_PURPOSE_FETCH_RENDDESC)
|
if (conn->purpose == DIR_PURPOSE_FETCH_RENDDESC)
|
||||||
rend_client_desc_fetched(conn->rend_query, 0);
|
rend_client_desc_here(conn->rend_query); /* give it a try */
|
||||||
break;
|
break;
|
||||||
case CONN_TYPE_OR:
|
case CONN_TYPE_OR:
|
||||||
/* Remember why we're closing this connection. */
|
/* Remember why we're closing this connection. */
|
||||||
@ -1243,9 +1243,11 @@ connection_t *connection_get_by_type_state_lastwritten(int type, int state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Return a connection of type <b>type</b> that has rendquery equal
|
/** Return a connection of type <b>type</b> that has rendquery equal
|
||||||
* to <b>rendquery</b>, and that is not marked for close.
|
* to <b>rendquery</b>, and that is not marked for close. If state
|
||||||
|
* is non-zero, conn must be of that state too.
|
||||||
*/
|
*/
|
||||||
connection_t *connection_get_by_type_rendquery(int type, const char *rendquery) {
|
connection_t *
|
||||||
|
connection_get_by_type_state_rendquery(int type, int state, const char *rendquery) {
|
||||||
int i, n;
|
int i, n;
|
||||||
connection_t *conn;
|
connection_t *conn;
|
||||||
connection_t **carray;
|
connection_t **carray;
|
||||||
@ -1255,6 +1257,7 @@ connection_t *connection_get_by_type_rendquery(int type, const char *rendquery)
|
|||||||
conn = carray[i];
|
conn = carray[i];
|
||||||
if (conn->type == type &&
|
if (conn->type == type &&
|
||||||
!conn->marked_for_close &&
|
!conn->marked_for_close &&
|
||||||
|
(!state || state == conn->state) &&
|
||||||
!rend_cmp_service_ids(rendquery, conn->rend_query))
|
!rend_cmp_service_ids(rendquery, conn->rend_query))
|
||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
|
@ -227,7 +227,7 @@ static int cpuworker_main(void *data) {
|
|||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
log_fn(LOG_INFO,"CPU worker exiting because Tor process closed connection (either rotated keys or died).");
|
log_fn(LOG_INFO,"CPU worker exiting because Tor process closed connection (either rotated keys or died).");
|
||||||
} else {
|
} else {
|
||||||
log_fn(LOG_INFO,"CPU worker editing because of error on connection To Tor process.");
|
log_fn(LOG_INFO,"CPU worker editing because of error on connection to Tor process.");
|
||||||
log_fn(LOG_INFO,"(Error on %d was %s)", fd, tor_socket_strerror(tor_socket_errno(fd)));
|
log_fn(LOG_INFO,"(Error on %d was %s)", fd, tor_socket_strerror(tor_socket_errno(fd)));
|
||||||
}
|
}
|
||||||
goto end;
|
goto end;
|
||||||
|
@ -746,8 +746,8 @@ connection_dir_client_reached_eof(connection_t *conn)
|
|||||||
* cleans it up */
|
* cleans it up */
|
||||||
} else {
|
} else {
|
||||||
/* success. notify pending connections about this. */
|
/* success. notify pending connections about this. */
|
||||||
rend_client_desc_fetched(conn->rend_query, 1);
|
|
||||||
conn->purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
|
conn->purpose = DIR_PURPOSE_HAS_FETCHED_RENDDESC;
|
||||||
|
rend_client_desc_here(conn->rend_query);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 404:
|
case 404:
|
||||||
|
@ -1206,7 +1206,7 @@ connection_t *connection_get_by_identity_digest(const char *digest, int type);
|
|||||||
connection_t *connection_get_by_type(int type);
|
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(int type, int state);
|
||||||
connection_t *connection_get_by_type_state_lastwritten(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, const char *rendquery);
|
connection_t *connection_get_by_type_state_rendquery(int type, int state, const char *rendquery);
|
||||||
|
|
||||||
#define connection_speaks_cells(conn) ((conn)->type == CONN_TYPE_OR)
|
#define connection_speaks_cells(conn) ((conn)->type == CONN_TYPE_OR)
|
||||||
#define connection_has_pending_tls_data(conn) \
|
#define connection_has_pending_tls_data(conn) \
|
||||||
@ -1495,7 +1495,7 @@ void rend_client_refetch_renddesc(const char *query);
|
|||||||
int rend_client_remove_intro_point(char *failed_intro, const char *query);
|
int rend_client_remove_intro_point(char *failed_intro, const char *query);
|
||||||
int rend_client_rendezvous_acked(circuit_t *circ, const char *request, size_t request_len);
|
int rend_client_rendezvous_acked(circuit_t *circ, const char *request, size_t request_len);
|
||||||
int rend_client_receive_rendezvous(circuit_t *circ, const char *request, size_t request_len);
|
int rend_client_receive_rendezvous(circuit_t *circ, const char *request, size_t request_len);
|
||||||
void rend_client_desc_fetched(char *query, int status);
|
void rend_client_desc_here(char *query);
|
||||||
|
|
||||||
char *rend_client_get_random_intro(char *query);
|
char *rend_client_get_random_intro(char *query);
|
||||||
|
|
||||||
|
@ -239,7 +239,7 @@ rend_client_introduction_acked(circuit_t *circ,
|
|||||||
void
|
void
|
||||||
rend_client_refetch_renddesc(const char *query)
|
rend_client_refetch_renddesc(const char *query)
|
||||||
{
|
{
|
||||||
if (connection_get_by_type_rendquery(CONN_TYPE_DIR, query)) {
|
if (connection_get_by_type_state_rendquery(CONN_TYPE_DIR, 0, query)) {
|
||||||
log_fn(LOG_INFO,"Would fetch a new renddesc here (for %s), but one is already in progress.", query);
|
log_fn(LOG_INFO,"Would fetch a new renddesc here (for %s), but one is already in progress.", query);
|
||||||
} else {
|
} else {
|
||||||
/* not one already; initiate a dir rend desc lookup */
|
/* not one already; initiate a dir rend desc lookup */
|
||||||
@ -258,6 +258,7 @@ rend_client_remove_intro_point(char *failed_intro, const char *query)
|
|||||||
{
|
{
|
||||||
int i, r;
|
int i, r;
|
||||||
rend_cache_entry_t *ent;
|
rend_cache_entry_t *ent;
|
||||||
|
connection_t *conn;
|
||||||
|
|
||||||
r = rend_cache_lookup_entry(query, &ent);
|
r = rend_cache_lookup_entry(query, &ent);
|
||||||
if (r<0) {
|
if (r<0) {
|
||||||
@ -282,6 +283,13 @@ rend_client_remove_intro_point(char *failed_intro, const char *query)
|
|||||||
if (!ent->parsed->n_intro_points) {
|
if (!ent->parsed->n_intro_points) {
|
||||||
log_fn(LOG_INFO,"No more intro points remain for %s. Re-fetching descriptor.", query);
|
log_fn(LOG_INFO,"No more intro points remain for %s. Re-fetching descriptor.", query);
|
||||||
rend_client_refetch_renddesc(query);
|
rend_client_refetch_renddesc(query);
|
||||||
|
|
||||||
|
/* move all pending streams back to renddesc_wait */
|
||||||
|
while ((conn = connection_get_by_type_state_rendquery(CONN_TYPE_AP,
|
||||||
|
AP_CONN_STATE_CIRCUIT_WAIT, query))) {
|
||||||
|
conn->state = AP_CONN_STATE_RENDDESC_WAIT;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
log_fn(LOG_INFO,"%d options left for %s.", ent->parsed->n_intro_points, query);
|
log_fn(LOG_INFO,"%d options left for %s.", ent->parsed->n_intro_points, query);
|
||||||
@ -366,30 +374,21 @@ rend_client_receive_rendezvous(circuit_t *circ, const char *request, size_t requ
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Find all the apconns in state AP_CONN_STATE_RENDDESC_WAIT that
|
/** Find all the apconns in state AP_CONN_STATE_RENDDESC_WAIT that
|
||||||
* are waiting on query. If status==1, move them to the next state.
|
* are waiting on query. If there's a working cache entry here
|
||||||
* If status==0, fail them.
|
* with at least one intro point, move them to the next state;
|
||||||
|
* else fail them.
|
||||||
*/
|
*/
|
||||||
void rend_client_desc_fetched(char *query, int status) {
|
void rend_client_desc_here(char *query) {
|
||||||
connection_t **carray;
|
|
||||||
connection_t *conn;
|
connection_t *conn;
|
||||||
int n, i;
|
|
||||||
rend_cache_entry_t *entry;
|
rend_cache_entry_t *entry;
|
||||||
|
|
||||||
get_connection_array(&carray, &n);
|
while ((conn = connection_get_by_type_state_rendquery(CONN_TYPE_AP,
|
||||||
|
AP_CONN_STATE_RENDDESC_WAIT, query))) {
|
||||||
for (i = 0; i < n; ++i) {
|
if (rend_cache_lookup_entry(conn->rend_query, &entry) == 1 &&
|
||||||
conn = carray[i];
|
entry->parsed->n_intro_points > 0) {
|
||||||
if (conn->type != CONN_TYPE_AP ||
|
|
||||||
conn->state != AP_CONN_STATE_RENDDESC_WAIT)
|
|
||||||
continue;
|
|
||||||
if (rend_cmp_service_ids(conn->rend_query, query))
|
|
||||||
continue;
|
|
||||||
/* great, this guy was waiting */
|
|
||||||
if (status!=0 ||
|
|
||||||
rend_cache_lookup_entry(conn->rend_query, &entry) == 1) {
|
|
||||||
/* either this fetch worked, or it failed but there was a
|
/* either this fetch worked, or it failed but there was a
|
||||||
* valid entry from before which we should reuse */
|
* valid entry from before which we should reuse */
|
||||||
log_fn(LOG_INFO,"Rend desc retrieved. Launching circuits.");
|
log_fn(LOG_INFO,"Rend desc is usable. Launching circuits.");
|
||||||
conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
|
conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
|
||||||
if (connection_ap_handshake_attach_circuit(conn) < 0) {
|
if (connection_ap_handshake_attach_circuit(conn) < 0) {
|
||||||
/* it will never work */
|
/* it will never work */
|
||||||
@ -397,8 +396,9 @@ void rend_client_desc_fetched(char *query, int status) {
|
|||||||
conn->has_sent_end = 1;
|
conn->has_sent_end = 1;
|
||||||
connection_mark_for_close(conn);
|
connection_mark_for_close(conn);
|
||||||
}
|
}
|
||||||
|
tor_assert(conn->state != AP_CONN_STATE_RENDDESC_WAIT); /* avoid loop */
|
||||||
} else { /* 404, or fetch didn't get that far */
|
} else { /* 404, or fetch didn't get that far */
|
||||||
log_fn(LOG_NOTICE,"Failed to fetch service id '%s', and not in cache. Closing conn.", query);
|
log_fn(LOG_NOTICE,"Closing stream for '%s.onion': hidden service is unavailable (try again later).", query);
|
||||||
conn->has_sent_end = 1;
|
conn->has_sent_end = 1;
|
||||||
connection_mark_for_close(conn);
|
connection_mark_for_close(conn);
|
||||||
}
|
}
|
||||||
|
@ -242,7 +242,9 @@ int rend_cache_lookup_desc(const char *query, const char **desc, size_t *desc_le
|
|||||||
/** Parse *desc, calculate its service id, and store it in the cache.
|
/** Parse *desc, calculate its service id, and store it in the cache.
|
||||||
* If we have a newer descriptor with the same ID, ignore this one.
|
* If we have a newer descriptor with the same ID, ignore this one.
|
||||||
* If we have an older descriptor with the same ID, replace it.
|
* If we have an older descriptor with the same ID, replace it.
|
||||||
* Returns -1 if it's malformed or otherwise rejected, else return 0.
|
* Return -1 if it's malformed or otherwise rejected; return 0 if
|
||||||
|
* it's the same or older than one we've already got; return 1 if
|
||||||
|
* it's novel.
|
||||||
*/
|
*/
|
||||||
int rend_cache_store(const char *desc, size_t desc_len)
|
int rend_cache_store(const char *desc, size_t desc_len)
|
||||||
{
|
{
|
||||||
@ -250,6 +252,7 @@ int rend_cache_store(const char *desc, size_t desc_len)
|
|||||||
rend_service_descriptor_t *parsed;
|
rend_service_descriptor_t *parsed;
|
||||||
char query[REND_SERVICE_ID_LEN+1];
|
char query[REND_SERVICE_ID_LEN+1];
|
||||||
time_t now;
|
time_t now;
|
||||||
|
|
||||||
tor_assert(rend_cache);
|
tor_assert(rend_cache);
|
||||||
parsed = rend_parse_service_descriptor(desc,desc_len);
|
parsed = rend_parse_service_descriptor(desc,desc_len);
|
||||||
if (!parsed) {
|
if (!parsed) {
|
||||||
@ -298,7 +301,7 @@ int rend_cache_store(const char *desc, size_t desc_len)
|
|||||||
memcpy(e->desc, desc, desc_len);
|
memcpy(e->desc, desc, desc_len);
|
||||||
|
|
||||||
log_fn(LOG_INFO,"Successfully stored rend desc '%s', len %d", query, (int)desc_len);
|
log_fn(LOG_INFO,"Successfully stored rend desc '%s', len %d", query, (int)desc_len);
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called when we get a rendezvous-related relay cell on circuit
|
/** Called when we get a rendezvous-related relay cell on circuit
|
||||||
|
Loading…
Reference in New Issue
Block a user