Browse Source

Merge branch 'bug3k_021' into bug3k_022

Conflicts:
	src/or/or.h
	src/or/rendclient.c
Sebastian Hahn 13 years ago
parent
commit
4b13ebd5ab
7 changed files with 100 additions and 23 deletions
  1. 9 0
      changes/forget-rend-descs-on-newnym
  2. 13 6
      src/or/circuituse.c
  3. 2 0
      src/or/main.c
  4. 64 17
      src/or/rendclient.c
  5. 1 0
      src/or/rendclient.h
  6. 10 0
      src/or/rendcommon.c
  7. 1 0
      src/or/rendcommon.h

+ 9 - 0
changes/forget-rend-descs-on-newnym

@@ -0,0 +1,9 @@
+  o Security fixes:
+    - Forget all hidden service descriptors cached as a client when
+      processing a SIGNAL NEWNYM command.  Fixes bug 3000.  Bugfix on
+      0.0.6.
+  o Code simplifications and refactoring:
+    - Allow rend_client_send_introduction to fail without closing the
+      AP connection permanently.
+
+

+ 13 - 6
src/or/circuituse.c

@@ -1744,14 +1744,21 @@ connection_ap_handshake_attach_circuit(edge_connection_t *conn)
                  "introduction. (stream %d sec old)",
                  introcirc->_base.n_circ_id, rendcirc->_base.n_circ_id,
                  conn_age);
-        if (rend_client_send_introduction(introcirc, rendcirc) < 0) {
+        switch (rend_client_send_introduction(introcirc, rendcirc)) {
+        case 0: /* success */
+          rendcirc->_base.timestamp_dirty = time(NULL);
+          introcirc->_base.timestamp_dirty = time(NULL);
+          assert_circuit_ok(TO_CIRCUIT(rendcirc));
+          assert_circuit_ok(TO_CIRCUIT(introcirc));
+          return 0;
+        case -1: /* transient error */
+          return 0;
+        case -2: /* permanent error */
+          return -1;
+        default: /* oops */
+          tor_fragile_assert();
           return -1;
         }
-        rendcirc->_base.timestamp_dirty = time(NULL);
-        introcirc->_base.timestamp_dirty = time(NULL);
-        assert_circuit_ok(TO_CIRCUIT(rendcirc));
-        assert_circuit_ok(TO_CIRCUIT(introcirc));
-        return 0;
       }
     }
 

+ 2 - 0
src/or/main.c

@@ -844,6 +844,8 @@ signewnym_impl(time_t now)
 {
   circuit_expire_all_dirty_circs();
   addressmap_clear_transient();
+  rend_cache_purge();
+  rend_client_cancel_descriptor_fetches();
   time_of_last_signewnym = now;
   signewnym_is_pending = 0;
 }

+ 64 - 17
src/or/rendclient.c

@@ -91,13 +91,25 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
 
   if (rend_cache_lookup_entry(introcirc->rend_data->onion_address, -1,
                               &entry) < 1) {
-    log_warn(LD_REND,
-             "query %s didn't have valid rend desc in cache. Failing.",
-             escaped_safe_str_client(introcirc->rend_data->onion_address));
-    goto err;
+    log_info(LD_REND,
+             "query %s didn't have valid rend desc in cache. "
+             "Refetching descriptor.",
+             safe_str(introcirc->rend_data->onion_address));
+    rend_client_refetch_v2_renddesc(introcirc->rend_data);
+    {
+      connection_t *conn;
+
+      while ((conn = connection_get_by_type_state_rendquery(CONN_TYPE_AP,
+                       AP_CONN_STATE_CIRCUIT_WAIT,
+                       introcirc->rend_data->onion_address))) {
+        conn->state = AP_CONN_STATE_RENDDESC_WAIT;
+      }
+    }
+
+    return -1;
   }
 
-  /* first 20 bytes of payload are the hash of the intro key */
+  /* first 20 bytes of payload are the hash of Bob's pk */
   intro_key = NULL;
   SMARTLIST_FOREACH(entry->parsed->intro_nodes, rend_intro_point_t *,
                     intro, {
@@ -108,15 +120,14 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
     }
   });
   if (!intro_key) {
-    log_info(LD_REND, "Our introduction point knowledge changed in "
-             "mid-connect! Could not find intro key; we only have a "
-             "v2 rend desc with %d intro points. Giving up.",
+    log_info(LD_REND, "Internal error: could not find intro key; we "
+             "only have a v2 rend desc with %d intro points.",
              smartlist_len(entry->parsed->intro_nodes));
-    goto err;
+    goto perm_err;
   }
   if (crypto_pk_get_digest(intro_key, payload)<0) {
     log_warn(LD_BUG, "Internal error: couldn't hash public key.");
-    goto err;
+    goto perm_err;
   }
 
   /* Initialize the pending_final_cpath and start the DH handshake. */
@@ -127,11 +138,11 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
     cpath->magic = CRYPT_PATH_MAGIC;
     if (!(cpath->dh_handshake_state = crypto_dh_new(DH_TYPE_REND))) {
       log_warn(LD_BUG, "Internal error: couldn't allocate DH.");
-      goto err;
+      goto perm_err;
     }
     if (crypto_dh_generate_public(cpath->dh_handshake_state)<0) {
       log_warn(LD_BUG, "Internal error: couldn't generate g^x.");
-      goto err;
+      goto perm_err;
     }
   }
 
@@ -181,7 +192,7 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
   if (crypto_dh_get_public(cpath->dh_handshake_state, tmp+dh_offset,
                            DH_KEY_LEN)<0) {
     log_warn(LD_BUG, "Internal error: couldn't extract g^x.");
-    goto err;
+    goto perm_err;
   }
 
   note_crypto_pk_op(REND_CLIENT);
@@ -194,7 +205,7 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
                                       PK_PKCS1_OAEP_PADDING, 0);
   if (r<0) {
     log_warn(LD_BUG,"Internal error: hybrid pk encrypt failed.");
-    goto err;
+    goto perm_err;
   }
 
   payload_len = DIGEST_LEN + r;
@@ -207,17 +218,17 @@ rend_client_send_introduction(origin_circuit_t *introcirc,
                                    introcirc->cpath->prev)<0) {
     /* introcirc is already marked for close. leave rendcirc alone. */
     log_warn(LD_BUG, "Couldn't send INTRODUCE1 cell");
-    return -1;
+    return -2;
   }
 
   /* Now, we wait for an ACK or NAK on this circuit. */
   introcirc->_base.purpose = CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT;
 
   return 0;
- err:
+perm_err:
   circuit_mark_for_close(TO_CIRCUIT(introcirc), END_CIRC_REASON_INTERNAL);
   circuit_mark_for_close(TO_CIRCUIT(rendcirc), END_CIRC_REASON_INTERNAL);
-  return -1;
+  return -2;
 }
 
 /** Called when a rendezvous circuit is open; sends a establish
@@ -526,8 +537,44 @@ rend_client_refetch_v2_renddesc(const rend_data_t *rend_query)
   return;
 }
 
+/** Cancel all rendezvous descriptor fetches currently in progress.
+ */
+void
+rend_client_cancel_descriptor_fetches(void)
+{
+  smartlist_t *connection_array = get_connection_array();
+
+  SMARTLIST_FOREACH_BEGIN(connection_array, connection_t *, conn) {
+    if (conn->type == CONN_TYPE_DIR &&
+        (conn->purpose == DIR_PURPOSE_FETCH_RENDDESC ||
+         conn->purpose == DIR_PURPOSE_FETCH_RENDDESC_V2)) {
+      /* It's a rendezvous descriptor fetch in progress -- cancel it
+       * by marking the connection for close.
+       *
+       * Even if this connection has already reached EOF, this is
+       * enough to make sure that if the descriptor hasn't been
+       * processed yet, it won't be.  See the end of
+       * connection_handle_read; connection_reached_eof (indirectly)
+       * processes whatever response the connection received. */
+
+      const rend_data_t *rd = (TO_DIR_CONN(conn))->rend_data;
+      if (!rd) {
+        log_warn(LD_BUG | LD_REND,
+                 "Marking for close dir conn fetching rendezvous "
+                 "descriptor for unknown service!");
+      } else {
+        log_debug(LD_REND, "Marking for close dir conn fetching "
+                  "rendezvous descriptor for service %s",
+                  safe_str(rd->onion_address));
+      }
+      connection_mark_for_close(conn);
+    }
+  } SMARTLIST_FOREACH_END(conn);
+}
+
 /** Remove failed_intro from ent. If ent now has no intro points, or
  * service is unrecognized, then launch a new renddesc fetch.
+
  *
  * Return -1 if error, 0 if no intro points remain or service
  * unrecognized, 1 if recognized and some intro points remain.

+ 1 - 0
src/or/rendclient.h

@@ -18,6 +18,7 @@ int rend_client_introduction_acked(origin_circuit_t *circ,
                                    const uint8_t *request,
                                    size_t request_len);
 void rend_client_refetch_v2_renddesc(const rend_data_t *rend_query);
+void rend_client_cancel_descriptor_fetches(void);
 int rend_client_remove_intro_point(extend_info_t *failed_intro,
                                    const rend_data_t *rend_query);
 int rend_client_rendezvous_acked(origin_circuit_t *circ,

+ 10 - 0
src/or/rendcommon.c

@@ -834,6 +834,16 @@ rend_cache_clean(void)
   }
 }
 
+/** Remove ALL entries from the rendezvous service descriptor cache.
+ */
+void
+rend_cache_purge(void)
+{
+  if (rend_cache)
+    strmap_free(rend_cache, _rend_cache_entry_free);
+  rend_cache = strmap_new();
+}
+
 /** Remove all old v2 descriptors and those for which this hidden service
  * directory is not responsible for any more. */
 void

+ 1 - 0
src/or/rendcommon.h

@@ -36,6 +36,7 @@ void rend_intro_point_free(rend_intro_point_t *intro);
 void rend_cache_init(void);
 void rend_cache_clean(void);
 void rend_cache_clean_v2_descs_as_dir(void);
+void rend_cache_purge(void);
 void rend_cache_free_all(void);
 int rend_valid_service_id(const char *query);
 int rend_cache_lookup_desc(const char *query, int version, const char **desc,