瀏覽代碼

Retry non-final-hop rendezvous failures

svn:r1625
Nick Mathewson 21 年之前
父節點
當前提交
37255d24bc
共有 4 個文件被更改,包括 57 次插入3 次删除
  1. 1 1
      doc/TODO
  2. 15 2
      src/or/circuit.c
  3. 3 0
      src/or/or.h
  4. 38 0
      src/or/rendservice.c

+ 1 - 1
doc/TODO

@@ -161,7 +161,7 @@ Rendezvous service:
         - cannibalize general circs?
         D how to set up multiple locations for a hidden service?
         o make bob publish only established intro circs?
-        - when bob tries to connect to alice's chosen rend point, but
+        o when bob tries to connect to alice's chosen rend point, but
           can't, but it's not the fault of the last hop in the rend
           circ, then he should retry?
 

+ 15 - 2
src/or/circuit.c

@@ -1253,7 +1253,14 @@ static void circuit_build_failed(circuit_t *circ) {
   /* we should examine circ and see if it failed because of
    * the last hop or an earlier hop. then use this info below.
    */
-  //int failed_at_last_hop;
+  int failed_at_last_hop = 0;
+  /* If the last hop isn't open, and the second-to-last is, we failed
+   * at the last hop. */
+  if (circ->cpath &&
+      circ->cpath->prev->state != CPATH_STATE_OPEN &&
+      circ->cpath->prev->prev->state == CPATH_STATE_OPEN) {
+      failed_at_last_hop = 1;
+  }
 
   switch(circ->purpose) {
     case CIRCUIT_PURPOSE_C_GENERAL:
@@ -1291,7 +1298,13 @@ static void circuit_build_failed(circuit_t *circ) {
       /* at Bob, connecting to rend point */
       /* Don't increment failure count, since Alice may have picked
        * the rendezvous point maliciously */
-      log_fn(LOG_INFO,"Couldn't connect to Alice's chosen rend point %s. Sucks to be Alice.", circ->build_state->chosen_exit);
+      if (failed_at_last_hop) {
+        log_fn(LOG_INFO,"Couldn't connect to Alice's chosen rend point %s. Sucks to be Alice.", circ->build_state->chosen_exit);
+      } else {
+        log_fn(LOG_INFO,"Couldn't connect to Alice's chosen rend point %s, because an earlier node failed.",
+               circ->build_state->chosen_exit);
+        rend_service_relaunch_rendezvous(circ);
+      }
       break;
     default:
       /* Other cases are impossible, since this function is only called with

+ 3 - 0
src/or/or.h

@@ -500,6 +500,8 @@ typedef struct {
   char *chosen_exit;
   /* cpath to append after rendezvous. */
   struct crypt_path_t *pending_final_cpath;
+  /* How many times has building a circuit for this task failed? */
+  int failure_count;
 } cpath_build_state_t;
 
 /* struct for a path (circuit) through the network */
@@ -1095,6 +1097,7 @@ void rend_service_intro_is_ready(circuit_t *circuit);
 int rend_service_intro_established(circuit_t *circuit, const char *request, int request_len);
 void rend_service_rendezvous_is_ready(circuit_t *circuit);
 int rend_service_introduce(circuit_t *circuit, const char *request, int request_len);
+void rend_service_relaunch_rendezvous(circuit_t *oldcirc);
 int rend_service_set_connection_addr_port(connection_t *conn, circuit_t *circ);
 void rend_service_dump_stats(int severity);
 

+ 38 - 0
src/or/rendservice.c

@@ -457,6 +457,44 @@ rend_service_introduce(circuit_t *circuit, const char *request, int request_len)
   return -1;
 }
 
+#define MAX_REND_FAILURES 3
+void
+rend_service_relaunch_rendezvous(circuit_t *oldcirc)
+{
+  circuit_t *newcirc;
+  cpath_build_state_t *newstate, *oldstate;
+
+  /* XXXX assert type and build_state */
+
+  if (!oldcirc->build_state ||
+      oldcirc->build_state->failure_count > MAX_REND_FAILURES) {
+    log_fn(LOG_INFO,"Attempt to build circuit to %s for rendezvous has failed too many times; giving up.",
+           oldcirc->build_state->chosen_exit);
+    return;
+  }
+
+  log_fn(LOG_INFO,"Reattempting rendezvous circuit to %s",
+         oldcirc->build_state->chosen_exit);
+
+  newcirc = circuit_launch_new(CIRCUIT_PURPOSE_S_CONNECT_REND,
+                               oldcirc->build_state->chosen_exit);
+  if (!newcirc) {
+    log_fn(LOG_WARN,"Couldn't relaunch rendezvous circuit to %s",
+           oldcirc->build_state->chosen_exit);
+    return;
+  }
+  oldstate = oldcirc->build_state;
+  newstate = newcirc->build_state;
+  assert(newstate && oldstate);
+  newstate->failure_count = oldstate->failure_count+1;
+  newstate->pending_final_cpath = oldstate->pending_final_cpath;
+  oldstate->pending_final_cpath = NULL;
+
+  memcpy(newcirc->rend_query, oldcirc->rend_query, REND_SERVICE_ID_LEN+1);
+  memcpy(newcirc->rend_pk_digest, oldcirc->rend_pk_digest, DIGEST_LEN);
+  memcpy(newcirc->rend_splice, oldcirc->rend_splice, REND_COOKIE_LEN);
+}
+
 /* Launch a circuit to serve as an introduction point.
  */
 static int