|  | @@ -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.
 |