Forráskód Böngészése

Merge branch 'bug15814_027_04'

Nick Mathewson 9 éve
szülő
commit
41efe22c03

+ 1 - 1
src/or/circuituse.c

@@ -2149,7 +2149,7 @@ link_apconn_to_circ(entry_connection_t *apconn, origin_circuit_t *circ,
      * that an attempt to connect to a hidden service just
      * succeeded.  Tell rendclient.c. */
     rend_client_note_connection_attempt_ended(
-                    ENTRY_TO_EDGE_CONN(apconn)->rend_data->onion_address);
+                    ENTRY_TO_EDGE_CONN(apconn)->rend_data);
   }
 
   if (cpath) { /* we were given one; use it */

+ 19 - 18
src/or/connection_edge.c

@@ -102,8 +102,7 @@ connection_mark_unattached_ap_,(entry_connection_t *conn, int endreason,
    * but we should fix it someday anyway. */
   if ((edge_conn->on_circuit != NULL || edge_conn->edge_has_sent_end) &&
       connection_edge_is_rendezvous_stream(edge_conn)) {
-    rend_client_note_connection_attempt_ended(
-                                    edge_conn->rend_data->onion_address);
+    rend_client_note_connection_attempt_ended(edge_conn->rend_data);
   }
 
   if (base_conn->marked_for_close) {
@@ -1499,12 +1498,27 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
       return -1;
     }
 
+    /* Look up if we have client authorization configured for this hidden
+     * service.  If we do, associate it with the rend_data. */
+    rend_service_authorization_t *client_auth =
+      rend_client_lookup_service_authorization(socks->address);
+
+    const char *cookie = NULL;
+    rend_auth_type_t auth_type = REND_NO_AUTH;
+    if (client_auth) {
+      log_info(LD_REND, "Using previously configured client authorization "
+               "for hidden service request.");
+      auth_type = client_auth->auth_type;
+      cookie = client_auth->descriptor_cookie;
+    }
+
     /* Fill in the rend_data field so we can start doing a connection to
      * a hidden service. */
     rend_data_t *rend_data = ENTRY_TO_EDGE_CONN(conn)->rend_data =
-      tor_malloc_zero(sizeof(rend_data_t));
-    strlcpy(rend_data->onion_address, socks->address,
-            sizeof(rend_data->onion_address));
+      rend_data_client_create(socks->address, NULL, cookie, auth_type);
+    if (rend_data == NULL) {
+      return -1;
+    }
     log_info(LD_REND,"Got a hidden service request for ID '%s'",
              safe_str_client(rend_data->onion_address));
 
@@ -1547,19 +1561,6 @@ connection_ap_handshake_rewrite_and_attach(entry_connection_t *conn,
       return 0;
     }
 
-    /* Look up if we have client authorization configured for this hidden
-     * service.  If we do, associate it with the rend_data. */
-    rend_service_authorization_t *client_auth =
-      rend_client_lookup_service_authorization(
-                                          rend_data->onion_address);
-    if (client_auth) {
-      log_info(LD_REND, "Using previously configured client authorization "
-                        "for hidden service request.");
-      memcpy(rend_data->descriptor_cookie,
-             client_auth->descriptor_cookie, REND_DESC_COOKIE_LEN);
-      rend_data->auth_type = client_auth->auth_type;
-    }
-
     /* We have the descriptor so launch a connection to the HS. */
     base_conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
     log_info(LD_REND, "Descriptor is here. Great.");

+ 12 - 16
src/or/control.c

@@ -3389,25 +3389,21 @@ handle_control_hsfetch(control_connection_t *conn, uint32_t len,
     }
   }
 
-  rend_query = tor_malloc_zero(sizeof(*rend_query));
-
-  if (hsaddress) {
-    strncpy(rend_query->onion_address, hsaddress,
-            sizeof(rend_query->onion_address));
-  } else if (desc_id) {
-    /* Using a descriptor ID, we force the user to provide at least one
-     * hsdir server using the SERVER= option. */
-    if (!hsdirs || !smartlist_len(hsdirs)) {
+  rend_query = rend_data_client_create(hsaddress, desc_id, NULL,
+                                       REND_NO_AUTH);
+  if (rend_query == NULL) {
+    connection_printf_to_buf(conn, "551 Error creating the HS query\r\n");
+    goto done;
+  }
+
+  /* Using a descriptor ID, we force the user to provide at least one
+   * hsdir server using the SERVER= option. */
+  if (desc_id && (!hsdirs || !smartlist_len(hsdirs))) {
       connection_printf_to_buf(conn, "512 %s option is required\r\n",
                                opt_server);
       goto done;
-    }
-    memcpy(rend_query->descriptor_id, desc_id,
-           sizeof(rend_query->descriptor_id));
-  } else {
-    /* We can't get in here because of the first argument check. */
-    tor_assert(0);
   }
+
   /* We are about to trigger HSDir fetch so send the OK now because after
    * that 650 event(s) are possible so better to have the 250 OK before them
    * to avoid out of order replies. */
@@ -3423,7 +3419,7 @@ done:
   smartlist_free(args);
   /* Contains data pointer that we don't own thus no cleanup. */
   smartlist_free(hsdirs);
-  tor_free(rend_query);
+  rend_data_free(rend_query);
 exit:
   return 0;
 }

+ 8 - 2
src/or/or.h

@@ -793,6 +793,11 @@ typedef struct rend_data_t {
   /** Onion address (without the .onion part) that a client requests. */
   char onion_address[REND_SERVICE_ID_LEN_BASE32+1];
 
+  /** Descriptor ID for each replicas computed from the onion address. If
+   * the onion address is empty, this array MUST be empty. We keep them so
+   * we know when to purge our entry in the last hsdir request table. */
+  char descriptor_id[REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS][DIGEST_LEN];
+
   /** (Optional) descriptor cookie that is used by a client. */
   char descriptor_cookie[REND_DESC_COOKIE_LEN];
 
@@ -800,8 +805,9 @@ typedef struct rend_data_t {
   rend_auth_type_t auth_type;
 
   /** Descriptor ID for a client request. The control port command HSFETCH
-   * can use this. */
-  char descriptor_id[DIGEST_LEN];
+   * uses this. It's set if the descriptor query should only use this
+   * descriptor ID. */
+  char desc_id_fetch[DIGEST_LEN];
 
   /** Hash of the hidden service's PK used by a service. */
   char rend_pk_digest[DIGEST_LEN];

+ 61 - 39
src/or/rendclient.c

@@ -474,9 +474,8 @@ rend_client_introduction_acked(origin_circuit_t *circ,
 
 /** Contains the last request times to hidden service directories for
  * certain queries; each key is a string consisting of the
- * concatenation of a base32-encoded HS directory identity digest, a
- * base32-encoded HS descriptor ID, and a hidden service address
- * (without the ".onion" part); each value is a pointer to a time_t
+ * concatenation of a base32-encoded HS directory identity digest and
+ * base32-encoded HS descriptor ID; each value is a pointer to a time_t
  * holding the time of the last request for that descriptor ID to that
  * HS directory. */
 static strmap_t *last_hid_serv_requests_ = NULL;
@@ -492,8 +491,7 @@ get_last_hid_serv_requests(void)
 }
 
 #define LAST_HID_SERV_REQUEST_KEY_LEN (REND_DESC_ID_V2_LEN_BASE32 + \
-                                       REND_DESC_ID_V2_LEN_BASE32 + \
-                                       REND_SERVICE_ID_LEN_BASE32)
+                                       REND_DESC_ID_V2_LEN_BASE32)
 
 /** Look up the last request time to hidden service directory <b>hs_dir</b>
  * for descriptor ID <b>desc_id_base32</b>. If <b>set</b> is non-zero,
@@ -554,20 +552,23 @@ directory_clean_last_hid_serv_requests(time_t now)
   }
 }
 
-/** Remove all requests related to the hidden service named
- * <b>onion_address</b> from the history of times of requests to
- * hidden service directories.
+/** Remove all requests related to the descriptor ID <b>desc_id</b> from the
+ * history of times of requests to hidden service directories.
+ * <b>desc_id</b> is an unencoded descriptor ID of size DIGEST_LEN.
  *
  * This is called from rend_client_note_connection_attempt_ended(), which
- * must be idempotent, so any future changes to this function must leave
- * it idempotent too.
- */
+ * must be idempotent, so any future changes to this function must leave it
+ * idempotent too. */
 static void
-purge_hid_serv_from_last_hid_serv_requests(const char *onion_address)
+purge_hid_serv_from_last_hid_serv_requests(const char *desc_id)
 {
   strmap_iter_t *iter;
   strmap_t *last_hid_serv_requests = get_last_hid_serv_requests();
-  /* XXX023 tor_assert(strlen(onion_address) == REND_SERVICE_ID_LEN_BASE32); */
+  char desc_id_base32[REND_DESC_ID_V2_LEN_BASE32 + 1];
+
+  /* Key is stored with the base32 encoded desc_id. */
+  base32_encode(desc_id_base32, sizeof(desc_id_base32), desc_id,
+                DIGEST_LEN);
   for (iter = strmap_iter_init(last_hid_serv_requests);
        !strmap_iter_done(iter); ) {
     const char *key;
@@ -575,9 +576,9 @@ purge_hid_serv_from_last_hid_serv_requests(const char *onion_address)
     strmap_iter_get(iter, &key, &val);
     /* XXX023 tor_assert(strlen(key) == LAST_HID_SERV_REQUEST_KEY_LEN); */
     if (tor_memeq(key + LAST_HID_SERV_REQUEST_KEY_LEN -
-                  REND_SERVICE_ID_LEN_BASE32,
-                  onion_address,
-                  REND_SERVICE_ID_LEN_BASE32)) {
+                  REND_DESC_ID_V2_LEN_BASE32,
+                  desc_id_base32,
+                  REND_DESC_ID_V2_LEN_BASE32)) {
       iter = strmap_iter_next_rmv(last_hid_serv_requests, iter);
       tor_free(val);
     } else {
@@ -791,8 +792,7 @@ end:
  * On success, 1 is returned. If no hidden service is left to ask, return 0.
  * On error, -1 is returned. */
 static int
-fetch_v2_desc_by_addr(const rend_data_t *query,
-                      smartlist_t *hsdirs)
+fetch_v2_desc_by_addr(rend_data_t *query, smartlist_t *hsdirs)
 {
   char descriptor_id[DIGEST_LEN];
   int replicas_left_to_try[REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS];
@@ -822,6 +822,16 @@ fetch_v2_desc_by_addr(const rend_data_t *query,
       goto end;
     }
 
+    if (tor_memcmp(descriptor_id, query->descriptor_id[chosen_replica],
+                   sizeof(descriptor_id)) != 0) {
+      /* Not equal from what we currently have so purge the last hid serv
+       * request cache and update the descriptor ID with the new value. */
+      purge_hid_serv_from_last_hid_serv_requests(
+                                        query->descriptor_id[chosen_replica]);
+      memcpy(query->descriptor_id[chosen_replica], descriptor_id,
+             sizeof(query->descriptor_id[chosen_replica]));
+    }
+
     /* Trigger the fetch with the computed descriptor ID. */
     ret = fetch_v2_desc_by_descid(descriptor_id, query, hsdirs);
     if (ret != 0) {
@@ -848,8 +858,7 @@ end:
  * On success, 1 is returned. If no hidden service is left to ask, return 0.
  * On error, -1 is returned. */
 int
-rend_client_fetch_v2_desc(const rend_data_t *query,
-                          smartlist_t *hsdirs)
+rend_client_fetch_v2_desc(rend_data_t *query, smartlist_t *hsdirs)
 {
   int ret;
 
@@ -860,8 +869,8 @@ rend_client_fetch_v2_desc(const rend_data_t *query,
 
   if (query->onion_address[0] != '\0') {
     ret = fetch_v2_desc_by_addr(query, hsdirs);
-  } else if (query->descriptor_id[0] != '\0') {
-    ret = fetch_v2_desc_by_descid(query->descriptor_id, query, hsdirs);
+  } else if (!tor_digest_is_zero(query->desc_id_fetch)) {
+    ret = fetch_v2_desc_by_descid(query->desc_id_fetch, query, hsdirs);
   } else {
     /* Query data is invalid. */
     ret = -1;
@@ -876,7 +885,7 @@ error:
  * one (possibly) working introduction point in it, start a connection to a
  * hidden service directory to fetch a v2 rendezvous service descriptor. */
 void
-rend_client_refetch_v2_renddesc(const rend_data_t *rend_query)
+rend_client_refetch_v2_renddesc(rend_data_t *rend_query)
 {
   int ret;
   rend_cache_entry_t *e = NULL;
@@ -963,7 +972,7 @@ rend_client_cancel_descriptor_fetches(void)
  */
 int
 rend_client_report_intro_point_failure(extend_info_t *failed_intro,
-                                       const rend_data_t *rend_query,
+                                       rend_data_t *rend_query,
                                        unsigned int failure_type)
 {
   int i, r;
@@ -1213,28 +1222,28 @@ rend_client_desc_trynow(const char *query)
                  "unavailable (try again later).",
                  safe_str_client(query));
       connection_mark_unattached_ap(conn, END_STREAM_REASON_RESOLVEFAILED);
-      rend_client_note_connection_attempt_ended(query);
+      rend_client_note_connection_attempt_ended(rend_data);
     }
   } SMARTLIST_FOREACH_END(base_conn);
 }
 
-/** Clear temporary state used only during an attempt to connect to
- * the hidden service named <b>onion_address</b>.  Called when a
- * connection attempt has ended; it is possible for this to be called
- * multiple times while handling an ended connection attempt, and
- * any future changes to this function must ensure it remains
- * idempotent.
- */
+/** Clear temporary state used only during an attempt to connect to the
+ * hidden service with <b>rend_data</b>. Called when a connection attempt
+ * has ended; it is possible for this to be called multiple times while
+ * handling an ended connection attempt, and any future changes to this
+ * function must ensure it remains idempotent. */
 void
-rend_client_note_connection_attempt_ended(const char *onion_address)
+rend_client_note_connection_attempt_ended(const rend_data_t *rend_data)
 {
+  unsigned int have_onion = 0;
   rend_cache_entry_t *cache_entry = NULL;
-  /* Ignore return value; we find an entry, or we don't. */
-  (void) rend_cache_lookup_entry(onion_address, -1, &cache_entry);
 
-  log_info(LD_REND, "Connection attempt for %s has ended; "
-           "cleaning up temporary state.",
-           safe_str_client(onion_address));
+  if (*rend_data->onion_address != '\0') {
+    /* Ignore return value; we find an entry, or we don't. */
+    (void) rend_cache_lookup_entry(rend_data->onion_address, -1,
+                                   &cache_entry);
+    have_onion = 1;
+  }
 
   /* Clear the timed_out flag on all remaining intro points for this HS. */
   if (cache_entry != NULL) {
@@ -1244,7 +1253,20 @@ rend_client_note_connection_attempt_ended(const char *onion_address)
   }
 
   /* Remove the HS's entries in last_hid_serv_requests. */
-  purge_hid_serv_from_last_hid_serv_requests(onion_address);
+  if (have_onion) {
+    unsigned int replica;
+    for (replica = 0; replica < ARRAY_LENGTH(rend_data->descriptor_id);
+         replica++) {
+      const char *desc_id = rend_data->descriptor_id[replica];
+      purge_hid_serv_from_last_hid_serv_requests(desc_id);
+    }
+    log_info(LD_REND, "Connection attempt for %s has ended; "
+             "cleaning up temporary state.",
+             safe_str_client(rend_data->onion_address));
+  } else {
+    /* We only have an ID for a fetch. Probably used by HSFETCH. */
+    purge_hid_serv_from_last_hid_serv_requests(rend_data->desc_id_fetch);
+  }
 }
 
 /** Return a newly allocated extend_info_t* for a randomly chosen introduction

+ 4 - 5
src/or/rendclient.h

@@ -19,9 +19,8 @@ void rend_client_rendcirc_has_opened(origin_circuit_t *circ);
 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);
-int rend_client_fetch_v2_desc(const rend_data_t *query,
-                              smartlist_t *hsdirs);
+void rend_client_refetch_v2_renddesc(rend_data_t *rend_query);
+int rend_client_fetch_v2_desc(rend_data_t *query, smartlist_t *hsdirs);
 void rend_client_cancel_descriptor_fetches(void);
 void rend_client_purge_last_hid_serv_requests(void);
 
@@ -30,7 +29,7 @@ void rend_client_purge_last_hid_serv_requests(void);
 #define INTRO_POINT_FAILURE_UNREACHABLE 2
 
 int rend_client_report_intro_point_failure(extend_info_t *failed_intro,
-                                           const rend_data_t *rend_query,
+                                           rend_data_t *rend_query,
                                            unsigned int failure_type);
 
 int rend_client_rendezvous_acked(origin_circuit_t *circ,
@@ -41,7 +40,7 @@ int rend_client_receive_rendezvous(origin_circuit_t *circ,
                                    size_t request_len);
 void rend_client_desc_trynow(const char *query);
 
-void rend_client_note_connection_attempt_ended(const char *onion_address);
+void rend_client_note_connection_attempt_ended(const rend_data_t *rend_data);
 
 extend_info_t *rend_client_get_random_intro(const rend_data_t *rend_query);
 int rend_client_any_intro_points_usable(const rend_cache_entry_t *entry);

+ 97 - 0
src/or/rendcommon.c

@@ -1404,3 +1404,100 @@ rend_data_dup(const rend_data_t *data)
   return tor_memdup(data, sizeof(rend_data_t));
 }
 
+/** Compute descriptor ID for each replicas and save them. A valid onion
+ * address must be present in the <b>rend_data</b>.
+ *
+ * Return 0 on success else -1. */
+static int
+compute_desc_id(rend_data_t *rend_data)
+{
+  int ret, replica;
+  time_t now = time(NULL);
+
+  tor_assert(rend_data);
+
+  /* Compute descriptor ID for each replicas. */
+  for (replica = 0; replica < ARRAY_LENGTH(rend_data->descriptor_id);
+       replica++) {
+    ret = rend_compute_v2_desc_id(rend_data->descriptor_id[replica],
+                                  rend_data->onion_address,
+                                  rend_data->descriptor_cookie,
+                                  now, replica);
+    if (ret < 0) {
+      goto end;
+    }
+  }
+
+end:
+  return ret;
+}
+
+/** Allocate and initialize a rend_data_t object for a service using the
+ * given arguments. Only the <b>onion_address</b> is not optional.
+ *
+ * Return a valid rend_data_t pointer. */
+rend_data_t *
+rend_data_service_create(const char *onion_address, const char *pk_digest,
+                         const uint8_t *cookie, rend_auth_type_t auth_type)
+{
+  rend_data_t *rend_data = tor_malloc_zero(sizeof(*rend_data));
+
+  /* We need at least one else the call is wrong. */
+  tor_assert(onion_address != NULL);
+
+  if (pk_digest) {
+    memcpy(rend_data->rend_pk_digest, pk_digest,
+           sizeof(rend_data->rend_pk_digest));
+  }
+  if (cookie) {
+    memcpy(rend_data->rend_cookie, cookie,
+           sizeof(rend_data->rend_cookie));
+  }
+
+  strlcpy(rend_data->onion_address, onion_address,
+          sizeof(rend_data->onion_address));
+  rend_data->auth_type = auth_type;
+
+  return rend_data;
+}
+
+/** Allocate and initialize a rend_data_t object for a client request using
+ * the given arguments.  Either an onion address or a descriptor ID is
+ * needed. Both can be given but only the onion address will be used to make
+ * the descriptor fetch.
+ *
+ * Return a valid rend_data_t pointer or NULL on error meaning the
+ * descriptor IDs couldn't be computed from the given data. */
+rend_data_t *
+rend_data_client_create(const char *onion_address, const char *desc_id,
+                        const char *cookie, rend_auth_type_t auth_type)
+{
+  rend_data_t *rend_data = tor_malloc_zero(sizeof(*rend_data));
+
+  /* We need at least one else the call is wrong. */
+  tor_assert(onion_address != NULL || desc_id != NULL);
+
+  if (cookie) {
+    memcpy(rend_data->descriptor_cookie, cookie,
+           sizeof(rend_data->descriptor_cookie));
+  }
+  if (desc_id) {
+    memcpy(rend_data->desc_id_fetch, desc_id,
+           sizeof(rend_data->desc_id_fetch));
+  }
+  if (onion_address) {
+    strlcpy(rend_data->onion_address, onion_address,
+            sizeof(rend_data->onion_address));
+    if (compute_desc_id(rend_data) < 0) {
+      goto error;
+    }
+  }
+
+  rend_data->auth_type = auth_type;
+
+  return rend_data;
+
+error:
+  rend_data_free(rend_data);
+  return NULL;
+}

+ 8 - 0
src/or/rendcommon.h

@@ -67,5 +67,13 @@ void rend_get_descriptor_id_bytes(char *descriptor_id_out,
                                   const char *secret_id_part);
 size_t rend_cache_get_total_allocation(void);
 
+rend_data_t *rend_data_client_create(const char *onion_address,
+                                     const char *desc_id,
+                                     const char *cookie,
+                                     rend_auth_type_t auth_type);
+rend_data_t *rend_data_service_create(const char *onion_address,
+                                      const char *pk_digest,
+                                      const uint8_t *cookie,
+                                      rend_auth_type_t auth_type);
 #endif
 

+ 8 - 11
src/or/rendservice.c

@@ -1735,13 +1735,11 @@ rend_service_introduce(origin_circuit_t *circuit, const uint8_t *request,
            hexcookie, serviceid);
   tor_assert(launched->build_state);
   /* Fill in the circuit's state. */
-  launched->rend_data = tor_malloc_zero(sizeof(rend_data_t));
-  memcpy(launched->rend_data->rend_pk_digest,
-         circuit->rend_data->rend_pk_digest,
-         DIGEST_LEN);
-  memcpy(launched->rend_data->rend_cookie, parsed_req->rc, REND_COOKIE_LEN);
-  strlcpy(launched->rend_data->onion_address, service->service_id,
-          sizeof(launched->rend_data->onion_address));
+
+  launched->rend_data =
+    rend_data_service_create(service->service_id,
+                             circuit->rend_data->rend_pk_digest,
+                             parsed_req->rc, service->auth_type);
 
   launched->build_state->service_pending_final_cpath_ref =
     tor_malloc_zero(sizeof(crypt_path_reference_t));
@@ -2713,10 +2711,9 @@ rend_service_launch_establish_intro(rend_service_t *service,
     intro->extend_info = extend_info_dup(launched->build_state->chosen_exit);
   }
 
-  launched->rend_data = tor_malloc_zero(sizeof(rend_data_t));
-  strlcpy(launched->rend_data->onion_address, service->service_id,
-          sizeof(launched->rend_data->onion_address));
-  memcpy(launched->rend_data->rend_pk_digest, service->pk_digest, DIGEST_LEN);
+  launched->rend_data = rend_data_service_create(service->service_id,
+                                                 service->pk_digest, NULL,
+                                                 service->auth_type);
   launched->intro_key = crypto_pk_dup_key(intro->intro_key);
   if (launched->base_.state == CIRCUIT_STATE_OPEN)
     rend_service_intro_has_opened(launched);