| 
					
				 | 
			
			
				@@ -20,6 +20,7 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "main.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "networkstatus.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "nodelist.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "policies.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "rendclient.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "rendcommon.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "rendservice.h" 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -107,59 +108,13 @@ struct rend_service_port_config_s { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * rendezvous point before giving up? */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #define MAX_REND_TIMEOUT 30 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-/** Represents a single hidden service running at this OP. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-typedef struct rend_service_t { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /* Fields specified in config file */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  char *directory; /**< where in the filesystem it stores it. Will be NULL if 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    * this service is ephemeral. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  int dir_group_readable; /**< if 1, allow group read 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                             permissions on directory */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  smartlist_t *ports; /**< List of rend_service_port_config_t */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  rend_auth_type_t auth_type; /**< Client authorization type or 0 if no client 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                               * authorization is performed. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  smartlist_t *clients; /**< List of rend_authorized_client_t's of 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                         * clients that may access our service. Can be NULL 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                         * if no client authorization is performed. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /* Other fields */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  crypto_pk_t *private_key; /**< Permanent hidden-service key. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  char service_id[REND_SERVICE_ID_LEN_BASE32+1]; /**< Onion address without 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                                  * '.onion' */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  char pk_digest[DIGEST_LEN]; /**< Hash of permanent hidden-service key. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  smartlist_t *intro_nodes; /**< List of rend_intro_point_t's we have, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                             * or are trying to establish. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /** List of rend_intro_point_t that are expiring. They are removed once 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-   * the new descriptor is successfully uploaded. A node in this list CAN 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-   * NOT appear in the intro_nodes list. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  smartlist_t *expiring_nodes; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  time_t intro_period_started; /**< Start of the current period to build 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                * introduction points. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  int n_intro_circuits_launched; /**< Count of intro circuits we have 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                  * established in this period. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  unsigned int n_intro_points_wanted; /**< Number of intro points this 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                       * service wants to have open. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  rend_service_descriptor_t *desc; /**< Current hidden service descriptor. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  time_t desc_is_dirty; /**< Time at which changes to the hidden service 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                         * descriptor content occurred, or 0 if it's 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                         * up-to-date. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  time_t next_upload_time; /**< Scheduled next hidden service descriptor 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            * upload time. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /** Replay cache for Diffie-Hellman values of INTRODUCE2 cells, to 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-   * detect repeats.  Clients may send INTRODUCE1 cells for the same 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-   * rendezvous point through two or more different introduction points; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-   * when they do, this keeps us from launching multiple simultaneous attempts 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-   * to connect to the same rend point. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  replaycache_t *accepted_intro_dh_parts; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /** If true, we don't close circuits for making requests to unsupported 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-   * ports. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  int allow_unknown_ports; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /** The maximum number of simultanious streams-per-circuit that are allowed 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-   * to be established, or 0 if no limit is set. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-   */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  int max_streams_per_circuit; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /** If true, we close circuits that exceed the max_streams_per_circuit 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-   * limit.  */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  int max_streams_close_circuit; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} rend_service_t; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* Hidden service directory file names: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * new file names should be added to rend_service_add_filenames_to_list() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * for sandboxing purposes. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static const char *private_key_fname = "private_key"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static const char *hostname_fname = "hostname"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static const char *client_keys_fname = "client_keys"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static const char *sos_poison_fname = "onion_service_non_anonymous"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /** Returns a escaped string representation of the service, <b>s</b>. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  */ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -206,16 +161,18 @@ rend_authorized_client_strmap_item_free(void *authorized_client) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /** Release the storage held by <b>service</b>. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static void 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+STATIC void 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 rend_service_free(rend_service_t *service) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (!service) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_free(service->directory); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  SMARTLIST_FOREACH(service->ports, rend_service_port_config_t*, p, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    rend_service_port_config_free(p)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  smartlist_free(service->ports); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (service->ports) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    SMARTLIST_FOREACH(service->ports, rend_service_port_config_t*, p, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      rend_service_port_config_free(p)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    smartlist_free(service->ports); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (service->private_key) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     crypto_pk_free(service->private_key); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (service->intro_nodes) { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1001,13 +958,235 @@ rend_service_update_descriptor(rend_service_t *service) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* Allocate and return a string containing the path to file_name in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * service->directory. Asserts that service has a directory. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * This function will never return NULL. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * The caller must free this path. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static char * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+rend_service_path(const rend_service_t *service, const char *file_name) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  char *file_path = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  tor_assert(service->directory); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* Can never fail: asserts rather than leaving file_path NULL. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  tor_asprintf(&file_path, "%s%s%s", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               service->directory, PATH_SEPARATOR, file_name); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return file_path; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* Allocate and return a string containing the path to the single onion 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * service poison file in service->directory. Asserts that service has a 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * directory. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * The caller must free this path. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+STATIC char * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+rend_service_sos_poison_path(const rend_service_t *service) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return rend_service_path(service, sos_poison_fname); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** Return True if hidden services <b>service> has been poisoned by single 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * onion mode. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+service_is_single_onion_poisoned(const rend_service_t *service) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  char *poison_fname = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  file_status_t fstatus; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!service->directory) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  poison_fname = rend_service_sos_poison_path(service); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  fstatus = file_status(poison_fname); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  tor_free(poison_fname); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* If this fname is occupied, the hidden service has been poisoned. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (fstatus == FN_FILE || fstatus == FN_EMPTY) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* Return 1 if the private key file for service exists and has a non-zero size, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * and 0 otherwise. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+rend_service_private_key_exists(const rend_service_t *service) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  char *private_key_path = rend_service_path(service, private_key_fname); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const file_status_t private_key_status = file_status(private_key_path); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  tor_free(private_key_path); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* Only non-empty regular private key files could have been used before. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return private_key_status == FN_FILE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** Check the single onion service poison state of all existing hidden service 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * directories: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * - If each service is poisoned, and we are in Single Onion Mode, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   return 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * - If each service is not poisoned, and we are not in Single Onion Mode, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   return 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * - Otherwise, the poison state is invalid, and a service that was created in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *   one mode is being used in the other, return -1. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Hidden service directories without keys are not checked for consistency. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * When their keys are created, they will be poisoned (if needed). 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * If a <b>service_list</b> is provided, treat it 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * as the list of hidden services (used in unittests). */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+rend_service_list_verify_single_onion_poison(const smartlist_t *service_list, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                             const or_options_t *options) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const smartlist_t *s_list; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* If no special service list is provided, then just use the global one. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!service_list) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!rend_service_list) { /* No global HS list. Nothing to see here. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    s_list = rend_service_list; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    s_list = service_list; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  int consistent = 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  SMARTLIST_FOREACH_BEGIN(s_list, const rend_service_t *, s) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (service_is_single_onion_poisoned(s) != 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        rend_service_non_anonymous_mode_enabled(options) && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        rend_service_private_key_exists(s)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      consistent = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } SMARTLIST_FOREACH_END(s); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return consistent ? 0 : -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/*** Helper for rend_service_poison_new_single_onion_dirs(). Add a file to 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * this hidden service directory that marks it as a single onion service. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Tor must be in single onion mode before calling this function. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Returns 0 when a directory is successfully poisoned, or if it is already 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * poisoned. Returns -1 on a failure to read the directory or write the poison 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * file, or if there is an existing private key file in the directory. (The 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * service should have been poisoned when the key was created.) */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+poison_new_single_onion_hidden_service_dir(const rend_service_t *service) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* We must only poison directories if we're in Single Onion mode */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  tor_assert(rend_service_non_anonymous_mode_enabled(get_options())); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  int fd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  int retval = -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  char *poison_fname = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!service->directory) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    log_info(LD_REND, "Ephemeral HS started in non-anonymous mode."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* Make sure we're only poisoning new hidden service directories */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (rend_service_private_key_exists(service)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    log_warn(LD_BUG, "Tried to single onion poison a service directory after " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             "the private key was created."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  poison_fname = rend_service_sos_poison_path(service); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  switch (file_status(poison_fname)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  case FN_DIR: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  case FN_ERROR: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    log_warn(LD_FS, "Can't read single onion poison file \"%s\"", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             poison_fname); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    goto done; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  case FN_FILE: /* single onion poison file already exists. NOP. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  case FN_EMPTY: /* single onion poison file already exists. NOP. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    log_debug(LD_FS, "Tried to re-poison a single onion poisoned file \"%s\"", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              poison_fname); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  case FN_NOENT: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fd = tor_open_cloexec(poison_fname, O_RDWR|O_CREAT|O_TRUNC, 0600); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (fd < 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      log_warn(LD_FS, "Could not create single onion poison file %s", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               poison_fname); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      goto done; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    close(fd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  default: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    tor_assert(0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  retval = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ done: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  tor_free(poison_fname); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return retval; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** We just got launched in Single Onion Mode. That's a non-anoymous 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * mode for hidden services; hence we should mark all new hidden service 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * directories appropriately so that they are never launched as 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * location-private hidden services again. (New directories don't have private 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * key files.) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * If a <b>service_list</b> is provided, treat it as the list of hidden 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * services (used in unittests). 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Return 0 on success, -1 on fail. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+rend_service_poison_new_single_onion_dirs(const smartlist_t *service_list) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* We must only poison directories if we're in Single Onion mode */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  tor_assert(rend_service_non_anonymous_mode_enabled(get_options())); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const smartlist_t *s_list; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* If no special service list is provided, then just use the global one. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!service_list) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!rend_service_list) { /* No global HS list. Nothing to see here. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    s_list = rend_service_list; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    s_list = service_list; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  SMARTLIST_FOREACH_BEGIN(s_list, const rend_service_t *, s) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!rend_service_private_key_exists(s)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (poison_new_single_onion_hidden_service_dir(s) < 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } SMARTLIST_FOREACH_END(s); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* The keys for these services are linked to the server IP address */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  log_notice(LD_REND, "The configured onion service directories have been " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             "used in single onion mode. They can not be used for anonymous " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             "hidden services."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /** Load and/or generate private keys for all hidden services, possibly 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * including keys for client authorization.  Return 0 on success, -1 on 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * failure. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * including keys for client authorization. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * If a <b>service_list</b> is provided, treat it as the list of hidden 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * services (used in unittests). Otherwise, require that rend_service_list is 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * not NULL. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Return 0 on success, -1 on failure. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-rend_service_load_all_keys(void) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+rend_service_load_all_keys(const smartlist_t *service_list) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  SMARTLIST_FOREACH_BEGIN(rend_service_list, rend_service_t *, s) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const smartlist_t *s_list; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* If no special service list is provided, then just use the global one. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!service_list) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    tor_assert(rend_service_list); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    s_list = rend_service_list; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    s_list = service_list; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  SMARTLIST_FOREACH_BEGIN(s_list, rend_service_t *, s) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (s->private_key) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     log_info(LD_REND, "Loading hidden-service keys from \"%s\"", 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1027,12 +1206,10 @@ rend_service_add_filenames_to_list(smartlist_t *lst, const rend_service_t *s) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(lst); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(s); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(s->directory); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  smartlist_add_asprintf(lst, "%s"PATH_SEPARATOR"private_key", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                         s->directory); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  smartlist_add_asprintf(lst, "%s"PATH_SEPARATOR"hostname", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                         s->directory); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  smartlist_add_asprintf(lst, "%s"PATH_SEPARATOR"client_keys", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                         s->directory); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  smartlist_add(lst, rend_service_path(s, private_key_fname)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  smartlist_add(lst, rend_service_path(s, hostname_fname)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  smartlist_add(lst, rend_service_path(s, client_keys_fname)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  smartlist_add(lst, rend_service_sos_poison_path(s)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /** Add to <b>open_lst</b> every filename used by a configured hidden service, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1076,7 +1253,7 @@ rend_service_derive_key_digests(struct rend_service_t *s) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 rend_service_load_keys(rend_service_t *s) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  char fname[512]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  char *fname = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   char buf[128]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   cpd_check_t  check_opts = CPD_CREATE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1085,7 +1262,7 @@ rend_service_load_keys(rend_service_t *s) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* Check/create directory */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (check_private_dir(s->directory, check_opts, get_options()->User) < 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    return -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    goto err; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #ifndef _WIN32 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (s->dir_group_readable) { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1097,34 +1274,23 @@ rend_service_load_keys(rend_service_t *s) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* Load key */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (strlcpy(fname,s->directory,sizeof(fname)) >= sizeof(fname) || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      strlcat(fname,PATH_SEPARATOR"private_key",sizeof(fname)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-         >= sizeof(fname)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    log_warn(LD_CONFIG, "Directory name too long to store key file: \"%s\".", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-             s->directory); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    return -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  fname = rend_service_path(s, private_key_fname); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   s->private_key = init_key_from_file(fname, 1, LOG_ERR, 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (!s->private_key) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    return -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    goto err; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (rend_service_derive_key_digests(s) < 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    return -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    goto err; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  tor_free(fname); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* Create service file */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (strlcpy(fname,s->directory,sizeof(fname)) >= sizeof(fname) || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      strlcat(fname,PATH_SEPARATOR"hostname",sizeof(fname)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      >= sizeof(fname)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    log_warn(LD_CONFIG, "Directory name too long to store hostname file:" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-             " \"%s\".", s->directory); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    return -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  fname = rend_service_path(s, hostname_fname); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_snprintf(buf, sizeof(buf),"%s.onion\n", s->service_id); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (write_str_to_file(fname,buf,0)<0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     log_warn(LD_CONFIG, "Could not write onion address to hostname file."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    memwipe(buf, 0, sizeof(buf)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    return -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    goto err; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #ifndef _WIN32 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (s->dir_group_readable) { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1135,15 +1301,21 @@ rend_service_load_keys(rend_service_t *s) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  memwipe(buf, 0, sizeof(buf)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* If client authorization is configured, load or generate keys. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (s->auth_type != REND_NO_AUTH) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    if (rend_service_load_auth_keys(s, fname) < 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      return -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (rend_service_load_auth_keys(s, fname) < 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      goto err; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  int r = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  goto done; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ err: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  r = -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ done: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  memwipe(buf, 0, sizeof(buf)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  tor_free(fname); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return r; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /** Load and/or generate client authorization keys for the hidden service 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1153,7 +1325,7 @@ static int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 rend_service_load_auth_keys(rend_service_t *s, const char *hfname) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   int r = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  char cfname[512]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  char *cfname = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   char *client_keys_str = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   strmap_t *parsed_clients = strmap_new(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   FILE *cfile, *hfile; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1163,12 +1335,7 @@ rend_service_load_auth_keys(rend_service_t *s, const char *hfname) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   char buf[1500]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* Load client keys and descriptor cookies, if available. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (tor_snprintf(cfname, sizeof(cfname), "%s"PATH_SEPARATOR"client_keys", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                   s->directory)<0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    log_warn(LD_CONFIG, "Directory name too long to store client keys " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-             "file: \"%s\".", s->directory); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    goto err; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  cfname = rend_service_path(s, client_keys_fname); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   client_keys_str = read_file_to_str(cfname, RFTS_IGNORE_MISSING, NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (client_keys_str) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (rend_parse_client_keys(parsed_clients, client_keys_str) < 0) { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1322,7 +1489,10 @@ rend_service_load_auth_keys(rend_service_t *s, const char *hfname) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   strmap_free(parsed_clients, rend_authorized_client_strmap_item_free); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  memwipe(cfname, 0, sizeof(cfname)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (cfname) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    memwipe(cfname, 0, sizeof(cfname)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    tor_free(cfname); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* Clear stack buffers that held key-derived material. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   memwipe(buf, 0, sizeof(buf)); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1424,6 +1594,31 @@ rend_check_authorization(rend_service_t *service, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   return 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* Can this service make a direct connection to ei? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * It must be a single onion service, and the firewall rules must allow ei. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+rend_service_use_direct_connection(const or_options_t* options, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                   const extend_info_t* ei) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* We'll connect directly all reachable addresses, whether preferred or not. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * The prefer_ipv6 argument to fascist_firewall_allows_address_addr is 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * ignored, because pref_only is 0. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return (rend_service_allow_non_anonymous_connection(options) && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          fascist_firewall_allows_address_addr(&ei->addr, ei->port, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                               FIREWALL_OR_CONNECTION, 0, 0)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* Like rend_service_use_direct_connection, but to a node. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+rend_service_use_direct_connection_node(const or_options_t* options, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                        const node_t* node) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* We'll connect directly all reachable addresses, whether preferred or not. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return (rend_service_allow_non_anonymous_connection(options) && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          fascist_firewall_allows_node(node, FIREWALL_OR_CONNECTION, 0)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /****** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * Handle cells 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  ******/ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1473,9 +1668,7 @@ rend_service_receive_introduction(origin_circuit_t *circuit, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     goto err; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-#ifndef NON_ANONYMOUS_MODE_ENABLED 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  tor_assert(!(circuit->build_state->onehop_tunnel)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  assert_circ_anonymity_ok(circuit, options); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(circuit->rend_data); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* We'll use this in a bazillion log messages */ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1679,6 +1872,11 @@ rend_service_receive_introduction(origin_circuit_t *circuit, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   for (i=0;i<MAX_REND_FAILURES;i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     int flags = CIRCLAUNCH_NEED_CAPACITY | CIRCLAUNCH_IS_INTERNAL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (circ_needs_uptime) flags |= CIRCLAUNCH_NEED_UPTIME; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /* A Single Onion Service only uses a direct connection if its 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * firewall rules permit direct connections to the address. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (rend_service_use_direct_connection(options, rp)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      flags = flags | CIRCLAUNCH_ONEHOP_TUNNEL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     launched = circuit_launch_by_extend_info( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         CIRCUIT_PURPOSE_S_CONNECT_REND, rp, flags); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1791,7 +1989,10 @@ find_rp_for_intro(const rend_intro_cell_t *intro, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       goto err; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    rp = extend_info_from_node(node, 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /* Are we in single onion mode? */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const int allow_direct = rend_service_allow_non_anonymous_connection( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                                get_options()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    rp = extend_info_from_node(node, allow_direct); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (!rp) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       if (err_msg_out) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         tor_asprintf(&err_msg, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1816,6 +2017,10 @@ find_rp_for_intro(const rend_intro_cell_t *intro, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     goto err; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* rp is always set here: extend_info_dup guarantees a non-NULL result, and 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * the other cases goto err. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  tor_assert(rp); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* Make sure the RP we are being asked to connect to is _not_ a private 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				    * address unless it's allowed. Let's avoid to build a circuit to our 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				    * second middle node and fail right after when extending to the RP. */ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -2590,6 +2795,10 @@ rend_service_relaunch_rendezvous(origin_circuit_t *oldcirc) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   log_info(LD_REND,"Reattempting rendezvous circuit to '%s'", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				            safe_str(extend_info_describe(oldstate->chosen_exit))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* You'd think Single Onion Services would want to retry the rendezvous 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * using a direct connection. But if it's blocked by a firewall, or the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * service is IPv6-only, or the rend point avoiding becoming a one-hop 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * proxy, we need a 3-hop connection. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   newcirc = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_CONNECT_REND, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                             oldstate->chosen_exit, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                             CIRCLAUNCH_NEED_CAPACITY|CIRCLAUNCH_IS_INTERNAL); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -2618,26 +2827,72 @@ rend_service_launch_establish_intro(rend_service_t *service, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                     rend_intro_point_t *intro) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   origin_circuit_t *launched; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  int flags = CIRCLAUNCH_NEED_UPTIME|CIRCLAUNCH_IS_INTERNAL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const or_options_t *options = get_options(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  extend_info_t *launch_ei = intro->extend_info; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  extend_info_t *direct_ei = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* Are we in single onion mode? */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (rend_service_allow_non_anonymous_connection(options)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /* Do we have a descriptor for the node? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * We've either just chosen it from the consensus, or we've just reviewed 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * our intro points to see which ones are still valid, and deleted the ones 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * that aren't in the consensus any more. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const node_t *node = node_get_by_id(launch_ei->identity_digest); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (BUG(!node)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      /* The service has kept an intro point after it went missing from the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       * consensus. If we did anything else here, it would be a consensus 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       * distinguisher. Which are less of an issue for single onion services, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       * but still a bug. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /* Can we connect to the node directly? If so, replace launch_ei 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * (a multi-hop extend_info) with one suitable for direct connection. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (rend_service_use_direct_connection_node(options, node)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      direct_ei = extend_info_from_node(node, 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (BUG(!direct_ei)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /* rend_service_use_direct_connection_node and extend_info_from_node 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         * disagree about which addresses on this node are permitted. This 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         * should never happen. Avoiding the connection is a safe response. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      flags = flags | CIRCLAUNCH_ONEHOP_TUNNEL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      launch_ei = direct_ei; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* launch_ei is either intro->extend_info, or has been replaced with a valid 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * extend_info for single onion service direct connection. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  tor_assert(launch_ei); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* We must have the same intro when making a direct connection. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  tor_assert(tor_memeq(intro->extend_info->identity_digest, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                       launch_ei->identity_digest, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                       DIGEST_LEN)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   log_info(LD_REND, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-           "Launching circuit to introduction point %s for service %s", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+           "Launching circuit to introduction point %s%s%s for service %s", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				            safe_str_client(extend_info_describe(intro->extend_info)), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+           direct_ei ? " via direct address " : "", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+           direct_ei ? safe_str_client(extend_info_describe(direct_ei)) : "", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				            service->service_id); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   rep_hist_note_used_internal(time(NULL), 1, 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   ++service->n_intro_circuits_launched; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   launched = circuit_launch_by_extend_info(CIRCUIT_PURPOSE_S_ESTABLISH_INTRO, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                             intro->extend_info, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                             CIRCLAUNCH_NEED_UPTIME|CIRCLAUNCH_IS_INTERNAL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                             launch_ei, flags); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (!launched) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     log_info(LD_REND, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-             "Can't launch circuit to establish introduction at %s.", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-             safe_str_client(extend_info_describe(intro->extend_info))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             "Can't launch circuit to establish introduction at %s%s%s.", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             safe_str_client(extend_info_describe(intro->extend_info)), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             direct_ei ? " via direct address " : "", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             direct_ei ? safe_str_client(extend_info_describe(direct_ei)) : "" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    extend_info_free(direct_ei); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /* We must have the same exit node even if cannibalized. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* We must have the same exit node even if cannibalized or direct connection. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(tor_memeq(intro->extend_info->identity_digest, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                        launched->build_state->chosen_exit->identity_digest, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                        DIGEST_LEN)); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -2648,6 +2903,7 @@ rend_service_launch_establish_intro(rend_service_t *service, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   launched->intro_key = crypto_pk_dup_key(intro->intro_key); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (launched->base_.state == CIRCUIT_STATE_OPEN) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     rend_service_intro_has_opened(launched); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  extend_info_free(direct_ei); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -2703,9 +2959,7 @@ rend_service_intro_has_opened(origin_circuit_t *circuit) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   int reason = END_CIRC_REASON_TORPROTOCOL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(circuit->base_.purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-#ifndef NON_ANONYMOUS_MODE_ENABLED 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  tor_assert(!(circuit->build_state->onehop_tunnel)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  assert_circ_anonymity_ok(circuit, get_options()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(circuit->cpath); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(circuit->rend_data); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -2772,6 +3026,7 @@ rend_service_intro_has_opened(origin_circuit_t *circuit) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   log_info(LD_REND, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				            "Established circuit %u as introduction point for service %s", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				            (unsigned)circuit->base_.n_circ_id, serviceid); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  circuit_log_path(LOG_INFO, LD_REND, circuit); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* Use the intro key instead of the service key in ESTABLISH_INTRO. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   crypto_pk_t *intro_key = circuit->intro_key; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -2901,9 +3156,7 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(circuit->base_.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(circuit->cpath); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(circuit->build_state); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-#ifndef NON_ANONYMOUS_MODE_ENABLED 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  tor_assert(!(circuit->build_state->onehop_tunnel)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-#endif 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  assert_circ_anonymity_ok(circuit, get_options()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   tor_assert(circuit->rend_data); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* Declare the circuit dirty to avoid reuse, and for path-bias */ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -2923,6 +3176,7 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				            "Done building circuit %u to rendezvous with " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				            "cookie %s for service %s", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				            (unsigned)circuit->base_.n_circ_id, hexcookie, serviceid); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  circuit_log_path(LOG_INFO, LD_REND, circuit); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* Clear the 'in-progress HS circ has timed out' flag for 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				    * consistency with what happens on the client side; this line has 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -3489,6 +3743,9 @@ rend_consider_services_intro_points(void) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   int i; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   time_t now; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   const or_options_t *options = get_options(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* Are we in single onion mode? */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const int allow_direct = rend_service_allow_non_anonymous_connection( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                                get_options()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* List of nodes we need to _exclude_ when choosing a new node to 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				    * establish an intro point to. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   smartlist_t *exclude_nodes; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -3584,8 +3841,24 @@ rend_consider_services_intro_points(void) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       router_crn_flags_t flags = CRN_NEED_UPTIME|CRN_NEED_DESC; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       if (get_options()->AllowInvalid_ & ALLOW_INVALID_INTRODUCTION) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         flags |= CRN_ALLOW_INVALID; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      router_crn_flags_t direct_flags = flags; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      direct_flags |= CRN_PREF_ADDR; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      direct_flags |= CRN_DIRECT_CONN; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       node = router_choose_random_node(exclude_nodes, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                       options->ExcludeNodes, flags); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                       options->ExcludeNodes, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                       allow_direct ? direct_flags : flags); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      /* If we are in single onion mode, retry node selection for a 3-hop 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       * path */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (allow_direct && !node) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        log_info(LD_REND, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                 "Unable to find an intro point that we can connect to " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                 "directly for %s, falling back to a 3-hop path.", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                 safe_str_client(service->service_id)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        node = router_choose_random_node(exclude_nodes, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                         options->ExcludeNodes, flags); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       if (!node) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         log_warn(LD_REND, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                  "We only have %d introduction points established for %s; " 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -3595,10 +3868,13 @@ rend_consider_services_intro_points(void) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                  n_intro_points_to_open); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      /* Add the choosen node to the exclusion list in order to avoid to 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-       * pick it again in the next iteration. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      /* Add the choosen node to the exclusion list in order to avoid picking 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       * it again in the next iteration. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       smartlist_add(exclude_nodes, (void*)node); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       intro = tor_malloc_zero(sizeof(rend_intro_point_t)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      /* extend_info is for clients, so we want the multi-hop primary ORPort, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       * even if we are a single onion service and intend to connect to it 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       * directly ourselves. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       intro->extend_info = extend_info_from_node(node, 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       intro->intro_key = crypto_pk_new(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       const int fail = crypto_pk_generate_key(intro->intro_key); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -3644,8 +3920,9 @@ rend_consider_services_upload(time_t now) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   int i; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   rend_service_t *service; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  int rendpostperiod = get_options()->RendPostPeriod; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  int rendinitialpostdelay = (get_options()->TestingTorNetwork ? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const or_options_t *options = get_options(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  int rendpostperiod = options->RendPostPeriod; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  int rendinitialpostdelay = (options->TestingTorNetwork ? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                               MIN_REND_INITIAL_POST_DELAY_TESTING : 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                               MIN_REND_INITIAL_POST_DELAY); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -3656,6 +3933,12 @@ rend_consider_services_upload(time_t now) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				        * the descriptor is stable before being published. See comment below. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       service->next_upload_time = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         now + rendinitialpostdelay + crypto_rand_int(2*rendpostperiod); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      /* Single Onion Services prioritise availability over hiding their 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       * startup time, as their IP address is publicly discoverable anyway. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (rend_service_reveal_startup_time(options)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        service->next_upload_time = now + rendinitialpostdelay; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /* Does every introduction points have been established? */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     unsigned int intro_points_ready = 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -3896,12 +4179,51 @@ rend_service_set_connection_addr_port(edge_connection_t *conn, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return -2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-/* Stub that should be replaced with the #17178 version of the function 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * when merging. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* Are HiddenServiceSingleHopMode and HiddenServiceNonAnonymousMode consistent? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+rend_service_non_anonymous_mode_consistent(const or_options_t *options) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* !! is used to make these options boolean */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return (!! options->HiddenServiceSingleHopMode == 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          !! options->HiddenServiceNonAnonymousMode); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* Do the options allow onion services to make direct (non-anonymous) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * connections to introduction or rendezvous points? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Must only be called after options_validate_single_onion() has successfully 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * checked onion service option consistency. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Returns true if tor is in HiddenServiceSingleHopMode. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-rend_service_allow_direct_connection(const or_options_t *options) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+rend_service_allow_non_anonymous_connection(const or_options_t *options) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  (void)options; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  tor_assert(rend_service_non_anonymous_mode_consistent(options)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return options->HiddenServiceSingleHopMode ? 1 : 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* Do the options allow us to reveal the exact startup time of the onion 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * service? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Single Onion Services prioritise availability over hiding their 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * startup time, as their IP address is publicly discoverable anyway. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Must only be called after options_validate_single_onion() has successfully 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * checked onion service option consistency. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Returns true if tor is in non-anonymous hidden service mode. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+rend_service_reveal_startup_time(const or_options_t *options) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  tor_assert(rend_service_non_anonymous_mode_consistent(options)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return rend_service_non_anonymous_mode_enabled(options); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* Is non-anonymous mode enabled using the HiddenServiceNonAnonymousMode 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * config option? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Must only be called after options_validate_single_onion() has successfully 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * checked onion service option consistency. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+rend_service_non_anonymous_mode_enabled(const or_options_t *options) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  tor_assert(rend_service_non_anonymous_mode_consistent(options)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return options->HiddenServiceNonAnonymousMode ? 1 : 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 |