|  | @@ -32,6 +32,58 @@
 | 
	
		
			
				|  |  |  #include "hs_ntor.h"
 | 
	
		
			
				|  |  |  #include "circuitbuild.h"
 | 
	
		
			
				|  |  |  #include "networkstatus.h"
 | 
	
		
			
				|  |  | +#include "reasons.h"
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* Return a human-readable string for the client fetch status code. */
 | 
	
		
			
				|  |  | +static const char *
 | 
	
		
			
				|  |  | +fetch_status_to_string(hs_client_fetch_status_t status)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  switch (status) {
 | 
	
		
			
				|  |  | +  case HS_CLIENT_FETCH_ERROR:
 | 
	
		
			
				|  |  | +    return "Internal error";
 | 
	
		
			
				|  |  | +  case HS_CLIENT_FETCH_LAUNCHED:
 | 
	
		
			
				|  |  | +    return "Descriptor fetch launched";
 | 
	
		
			
				|  |  | +  case HS_CLIENT_FETCH_HAVE_DESC:
 | 
	
		
			
				|  |  | +    return "Already have descriptor";
 | 
	
		
			
				|  |  | +  case HS_CLIENT_FETCH_NO_HSDIRS:
 | 
	
		
			
				|  |  | +    return "No more HSDir available to query";
 | 
	
		
			
				|  |  | +  case HS_CLIENT_FETCH_NOT_ALLOWED:
 | 
	
		
			
				|  |  | +    return "Fetching descriptors is not allowed";
 | 
	
		
			
				|  |  | +  case HS_CLIENT_FETCH_MISSING_INFO:
 | 
	
		
			
				|  |  | +    return "Missing directory information";
 | 
	
		
			
				|  |  | +  case HS_CLIENT_FETCH_PENDING:
 | 
	
		
			
				|  |  | +    return "Pending descriptor fetch";
 | 
	
		
			
				|  |  | +  default:
 | 
	
		
			
				|  |  | +    return "(Unknown client fetch status code)";
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/* Return true iff tor should close the SOCKS request(s) for the descriptor
 | 
	
		
			
				|  |  | + * fetch that ended up with this given status code. */
 | 
	
		
			
				|  |  | +static int
 | 
	
		
			
				|  |  | +fetch_status_should_close_socks(hs_client_fetch_status_t status)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  switch (status) {
 | 
	
		
			
				|  |  | +  case HS_CLIENT_FETCH_NO_HSDIRS:
 | 
	
		
			
				|  |  | +    /* No more HSDir to query, we can't complete the SOCKS request(s). */
 | 
	
		
			
				|  |  | +  case HS_CLIENT_FETCH_ERROR:
 | 
	
		
			
				|  |  | +    /* The fetch triggered an internal error. */
 | 
	
		
			
				|  |  | +  case HS_CLIENT_FETCH_NOT_ALLOWED:
 | 
	
		
			
				|  |  | +    /* Client is not allowed to fetch (FetchHidServDescriptors 0). */
 | 
	
		
			
				|  |  | +    goto close;
 | 
	
		
			
				|  |  | +  case HS_CLIENT_FETCH_MISSING_INFO:
 | 
	
		
			
				|  |  | +  case HS_CLIENT_FETCH_HAVE_DESC:
 | 
	
		
			
				|  |  | +  case HS_CLIENT_FETCH_PENDING:
 | 
	
		
			
				|  |  | +  case HS_CLIENT_FETCH_LAUNCHED:
 | 
	
		
			
				|  |  | +    /* The rest doesn't require tor to close the SOCKS request(s). */
 | 
	
		
			
				|  |  | +    goto no_close;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | + no_close:
 | 
	
		
			
				|  |  | +  return 0;
 | 
	
		
			
				|  |  | + close:
 | 
	
		
			
				|  |  | +  return 1;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /* Cancel all descriptor fetches currently in progress. */
 | 
	
		
			
				|  |  |  static void
 | 
	
	
		
			
				|  | @@ -136,6 +188,51 @@ directory_request_is_pending(const ed25519_public_key_t *identity_pk)
 | 
	
		
			
				|  |  |    return ret;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/* We failed to fetch a descriptor for the service with <b>identity_pk</b>
 | 
	
		
			
				|  |  | + * because of <b>status</b>. Find all pending SOCKS connections for this
 | 
	
		
			
				|  |  | + * service that are waiting on the descriptor and close them with
 | 
	
		
			
				|  |  | + * <b>reason</b>. */
 | 
	
		
			
				|  |  | +static void
 | 
	
		
			
				|  |  | +close_all_socks_conns_waiting_for_desc(const ed25519_public_key_t *identity_pk,
 | 
	
		
			
				|  |  | +                                       hs_client_fetch_status_t status,
 | 
	
		
			
				|  |  | +                                       int reason)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +  unsigned int count = 0;
 | 
	
		
			
				|  |  | +  time_t now = approx_time();
 | 
	
		
			
				|  |  | +  smartlist_t *conns =
 | 
	
		
			
				|  |  | +    connection_list_by_type_state(CONN_TYPE_AP, AP_CONN_STATE_RENDDESC_WAIT);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  SMARTLIST_FOREACH_BEGIN(conns, connection_t *, base_conn) {
 | 
	
		
			
				|  |  | +    entry_connection_t *entry_conn = TO_ENTRY_CONN(base_conn);
 | 
	
		
			
				|  |  | +    const edge_connection_t *edge_conn = ENTRY_TO_EDGE_CONN(entry_conn);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /* Only consider the entry connections that matches the service for which
 | 
	
		
			
				|  |  | +     * we tried to get the descriptor */
 | 
	
		
			
				|  |  | +    if (!edge_conn->hs_ident ||
 | 
	
		
			
				|  |  | +        !ed25519_pubkey_eq(identity_pk,
 | 
	
		
			
				|  |  | +                           &edge_conn->hs_ident->identity_pk)) {
 | 
	
		
			
				|  |  | +      continue;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    assert_connection_ok(base_conn, now);
 | 
	
		
			
				|  |  | +    /* Unattach the entry connection which will close for the reason. */
 | 
	
		
			
				|  |  | +    connection_mark_unattached_ap(entry_conn, reason);
 | 
	
		
			
				|  |  | +    count++;
 | 
	
		
			
				|  |  | +  } SMARTLIST_FOREACH_END(base_conn);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  if (count > 0) {
 | 
	
		
			
				|  |  | +    char onion_address[HS_SERVICE_ADDR_LEN_BASE32 + 1];
 | 
	
		
			
				|  |  | +    hs_build_address(identity_pk, HS_VERSION_THREE, onion_address);
 | 
	
		
			
				|  |  | +    log_notice(LD_REND, "Closed %u streams for service %s.onion "
 | 
	
		
			
				|  |  | +                        "for reason %s. Fetch status: %s.",
 | 
	
		
			
				|  |  | +               count, safe_str_client(onion_address),
 | 
	
		
			
				|  |  | +               stream_end_reason_to_string(reason),
 | 
	
		
			
				|  |  | +               fetch_status_to_string(status));
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /* No ownership of the object(s) in this list. */
 | 
	
		
			
				|  |  | +  smartlist_free(conns);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  /* A v3 HS circuit successfully connected to the hidden service. Update the
 | 
	
		
			
				|  |  |   * stream state at <b>hs_conn_ident</b> appropriately. */
 | 
	
		
			
				|  |  |  static void
 | 
	
	
		
			
				|  | @@ -1037,6 +1134,8 @@ hs_client_any_intro_points_usable(const ed25519_public_key_t *service_pk,
 | 
	
		
			
				|  |  |  int
 | 
	
		
			
				|  |  |  hs_client_refetch_hsdesc(const ed25519_public_key_t *identity_pk)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | +  int ret;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    tor_assert(identity_pk);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* Are we configured to fetch descriptors? */
 | 
	
	
		
			
				|  | @@ -1080,7 +1179,17 @@ hs_client_refetch_hsdesc(const ed25519_public_key_t *identity_pk)
 | 
	
		
			
				|  |  |      return HS_CLIENT_FETCH_PENDING;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  return fetch_v3_desc(identity_pk);
 | 
	
		
			
				|  |  | +  /* Try to fetch the desc and if we encounter an unrecoverable error, mark the
 | 
	
		
			
				|  |  | +   * desc as unavailable for now. */
 | 
	
		
			
				|  |  | +  ret = fetch_v3_desc(identity_pk);
 | 
	
		
			
				|  |  | +  if (fetch_status_should_close_socks(ret)) {
 | 
	
		
			
				|  |  | +    close_all_socks_conns_waiting_for_desc(identity_pk, ret,
 | 
	
		
			
				|  |  | +                                           END_STREAM_REASON_RESOLVEFAILED);
 | 
	
		
			
				|  |  | +    /* Remove HSDir fetch attempts so that we can retry later if the user
 | 
	
		
			
				|  |  | +     * wants us to regardless of if we closed any connections. */
 | 
	
		
			
				|  |  | +    purge_hid_serv_request(identity_pk);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  return ret;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /* This is called when we are trying to attach an AP connection to these
 |