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