| 
					
				 | 
			
			
				@@ -21,8 +21,9 @@ extern circuit_t *global_circuitlist; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 circuit_deliver_create_cell(circuit_t *circ, char *payload); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static cpath_build_state_t *onion_new_cpath_build_state(uint8_t purpose, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                                   const char *exit_digest); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static cpath_build_state_t * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+onion_new_cpath_build_state(uint8_t purpose, const char *exit_digest, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            int need_uptime, int need_capacity); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static int onion_extend_cpath(crypt_path_t **head_ptr, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                        cpath_build_state_t *state, routerinfo_t **router_out); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static int count_acceptable_routers(smartlist_t *routers); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -233,15 +234,17 @@ void circuit_dump_by_conn(connection_t *conn, int severity) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * Also launch a connection to the first OR in the chosen path, if 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * it's not open already. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-circuit_t *circuit_establish_circuit(uint8_t purpose, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                     const char *exit_digest) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+circuit_t * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+circuit_establish_circuit(uint8_t purpose, const char *exit_digest, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          int need_uptime, int need_capacity) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   routerinfo_t *firsthop; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   connection_t *n_conn; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   circuit_t *circ; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   circ = circuit_new(0, NULL); /* sets circ->p_circ_id and circ->p_conn */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   circ->state = CIRCUIT_STATE_OR_WAIT; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  circ->build_state = onion_new_cpath_build_state(purpose, exit_digest); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  circ->build_state = onion_new_cpath_build_state(purpose, exit_digest, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                  need_uptime, need_capacity); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   circ->purpose = purpose; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (! circ->build_state) { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -811,13 +814,24 @@ circuit_get_unhandled_ports(time_t now) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /** Return 1 if we already have circuits present or on the way for 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * all anticipated ports. Return 0 if we should make more. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * If we're returning 0, set need_uptime and need_capacity to 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * indicate any requirements that the unhandled ports have. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-circuit_all_predicted_ports_handled(time_t now) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  int enough; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+circuit_all_predicted_ports_handled(time_t now, int *need_uptime, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                    int *need_capacity) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  int i, enough; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  uint16_t *port; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   smartlist_t *sl = circuit_get_unhandled_ports(now); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  smartlist_t *LongLivedServices = get_options()->LongLivedPorts; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   enough = (smartlist_len(sl) == 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  SMARTLIST_FOREACH(sl, uint16_t *, cp, tor_free(cp)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  for (i = 0; i < smartlist_len(sl); ++i) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    port = smartlist_get(sl, i); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (smartlist_string_num_isin(LongLivedServices, *port)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      *need_uptime = 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    tor_free(port); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   smartlist_free(sl); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   return enough; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -853,7 +867,9 @@ router_handles_some_port(routerinfo_t *router, smartlist_t *needed_ports) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * Return NULL if we can't find any suitable routers. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static routerinfo_t *choose_good_exit_server_general(routerlist_t *dir) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static routerinfo_t * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+choose_good_exit_server_general(routerlist_t *dir, int need_uptime, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                int need_capacity) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   int *n_supported; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   int i, j; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -905,9 +921,13 @@ static routerinfo_t *choose_good_exit_server_general(routerlist_t *dir) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 //             router->nickname, i); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       continue; /* skip routers that are known to be down */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (router_is_unreliable(router, need_uptime, need_capacity)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      n_supported[i] = -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      continue; /* skip routers that are not suitable */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (!router->is_verified && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         (!(options->_AllowUnverified & ALLOW_UNVERIFIED_EXIT) || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-         router_is_unreliable_router(router, 1, 1))) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         router_is_unreliable(router, 1, 1))) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       /* if it's unverified, and either we don't want it or it's unsuitable */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       n_supported[i] = -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 //      log_fn(LOG_DEBUG,"Skipping node %s (index %d) -- unverified router.", 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1035,16 +1055,19 @@ static routerinfo_t *choose_good_exit_server_general(routerlist_t *dir) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * For client-side rendezvous circuits, choose a random node, weighted 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * toward the preferences in 'options'. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static routerinfo_t *choose_good_exit_server(uint8_t purpose, routerlist_t *dir) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static routerinfo_t * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+choose_good_exit_server(uint8_t purpose, routerlist_t *dir, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        int need_uptime, int need_capacity) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   routerinfo_t *r; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   or_options_t *options = get_options(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   switch (purpose) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     case CIRCUIT_PURPOSE_C_GENERAL: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      return choose_good_exit_server_general(dir); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return choose_good_exit_server_general(dir, need_uptime, need_capacity); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     case CIRCUIT_PURPOSE_C_ESTABLISH_REND: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       r = router_choose_random_node(options->RendNodes, options->RendExcludeNodes, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          NULL, 0, 1, options->_AllowUnverified & ALLOW_UNVERIFIED_RENDEZVOUS, 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          NULL, need_uptime, need_capacity, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          options->_AllowUnverified & ALLOW_UNVERIFIED_RENDEZVOUS, 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       return r; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   log_fn(LOG_WARN,"Bug: unhandled purpose %d", purpose); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1056,7 +1079,8 @@ static routerinfo_t *choose_good_exit_server(uint8_t purpose, routerlist_t *dir) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * return it. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static cpath_build_state_t * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-onion_new_cpath_build_state(uint8_t purpose, const char *exit_digest) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+onion_new_cpath_build_state(uint8_t purpose, const char *exit_digest, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            int need_uptime, int need_capacity) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   routerlist_t *rl; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   int r; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1071,6 +1095,8 @@ onion_new_cpath_build_state(uint8_t purpose, const char *exit_digest) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   info = tor_malloc_zero(sizeof(cpath_build_state_t)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   info->desired_path_len = r; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  info->need_uptime = need_uptime; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  info->need_capacity = need_capacity; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (exit_digest) { /* the circuit-builder pre-requested one */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     memcpy(info->chosen_exit_digest, exit_digest, DIGEST_LEN); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     exit = router_get_by_digest(exit_digest); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1083,7 +1109,7 @@ onion_new_cpath_build_state(uint8_t purpose, const char *exit_digest) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     log_fn(LOG_INFO,"Using requested exit node '%s'", info->chosen_exit_name); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } else { /* we have to decide one */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    exit = choose_good_exit_server(purpose, rl); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    exit = choose_good_exit_server(purpose, rl, need_uptime, need_capacity); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (!exit) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       log_fn(LOG_WARN,"failed to choose an exit server"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       tor_free(info); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1169,7 +1195,8 @@ static routerinfo_t *choose_good_middle_server(cpath_build_state_t *state, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   choice = router_choose_random_node(NULL, get_options()->ExcludeNodes, excluded, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-           0, 1, get_options()->_AllowUnverified & ALLOW_UNVERIFIED_MIDDLE, 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+           state->need_uptime, state->need_capacity, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+           get_options()->_AllowUnverified & ALLOW_UNVERIFIED_MIDDLE, 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   smartlist_free(excluded); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   return choice; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1179,7 +1206,6 @@ static routerinfo_t *choose_good_entry_server(cpath_build_state_t *state) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   routerinfo_t *r, *choice; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   smartlist_t *excluded = smartlist_create(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   or_options_t *options = get_options(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  char buf[16]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if ((r = router_get_by_digest(state->chosen_exit_digest))) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     smartlist_add(excluded, r); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1200,13 +1226,13 @@ static routerinfo_t *choose_good_entry_server(cpath_build_state_t *state) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     for (i=0; i < smartlist_len(rl->routers); i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       r = smartlist_get(rl->routers, i); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      tor_snprintf(buf, sizeof(buf), "%d", r->or_port); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      if (!smartlist_string_isin(options->FirewallPorts, buf)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (!smartlist_string_num_isin(options->FirewallPorts, r->or_port)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				          smartlist_add(excluded, r); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   choice = router_choose_random_node(options->EntryNodes, options->ExcludeNodes, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-           excluded, 0, 1, options->_AllowUnverified & ALLOW_UNVERIFIED_ENTRY, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+           excluded, state->need_uptime, state->need_capacity, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+           options->_AllowUnverified & ALLOW_UNVERIFIED_ENTRY, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				            options->StrictEntryNodes); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   smartlist_free(excluded); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   return choice; 
			 |