| 
					
				 | 
			
			
				@@ -53,6 +53,10 @@ static int circuit_resume_edge_reading_helper(edge_connection_t *conn, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static int circuit_consider_stop_edge_reading(circuit_t *circ, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                               crypt_path_t *layer_hint); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static int circuit_queue_streams_are_blocked(circuit_t *circ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void adjust_exit_policy_from_exitpolicy_failure(origin_circuit_t *circ, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                  entry_connection_t *conn, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                  node_t *node, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                  const tor_addr_t *addr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /** Stop reading on edge connections when we have this many cells 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * waiting on the appropriate queue. */ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -710,7 +714,6 @@ connection_ap_process_end_not_open( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     relay_header_t *rh, cell_t *cell, origin_circuit_t *circ, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     entry_connection_t *conn, crypt_path_t *layer_hint) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  struct in_addr in; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   node_t *exitrouter; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   int reason = *(cell->payload+RELAY_HEADER_SIZE); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   int control_reason; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -753,10 +756,10 @@ connection_ap_process_end_not_open( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				              stream_end_reason_to_string(reason)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     exitrouter = node_get_mutable_by_id(chosen_exit_digest); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     switch (reason) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      case END_STREAM_REASON_EXITPOLICY: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      case END_STREAM_REASON_EXITPOLICY: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        tor_addr_t addr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        tor_addr_make_unspec(&addr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if (rh->length >= 5) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          tor_addr_t addr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           int ttl = -1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           tor_addr_make_unspec(&addr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           if (rh->length == 5 || rh->length == 9) { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -808,16 +811,11 @@ connection_ap_process_end_not_open( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /* check if he *ought* to have allowed it */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if (exitrouter && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            (rh->length < 5 || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-             (tor_inet_aton(conn->socks_request->address, &in) && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              !conn->chosen_exit_name))) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          log_info(LD_APP, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                 "Exitrouter %s seems to be more restrictive than its exit " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                 "policy. Not using this router as exit for now.", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                 node_describe(exitrouter)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          policies_set_node_exitpolicy_to_reject_all(exitrouter); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        adjust_exit_policy_from_exitpolicy_failure(circ, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                   conn, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                   exitrouter, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                   &addr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if (conn->chosen_exit_optional || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             conn->chosen_exit_retries) { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -837,6 +835,7 @@ connection_ap_process_end_not_open( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /* else, conn will get closed below */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       case END_STREAM_REASON_CONNECTREFUSED: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if (!conn->chosen_exit_optional) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           break; /* break means it'll close, below */ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -901,6 +900,47 @@ connection_ap_process_end_not_open( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   return 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** Called when we have gotten an END_REASON_EXITPOLICY failure on <b>circ</b> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * for <b>conn</b>, while attempting to connect via <b>node</b>.  If the node 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * told us which address it rejected, then <b>addr</b> is that address; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * otherwise it is AF_UNSPEC. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * If we are sure the node should have allowed this address, mark the node as 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * having a reject *:* exit policy.  Otherwise, mark the circuit as unusable 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * for this particular address. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ **/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+adjust_exit_policy_from_exitpolicy_failure(origin_circuit_t *circ, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                           entry_connection_t *conn, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                           node_t *node, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                           const tor_addr_t *addr) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  int make_reject_all = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const sa_family_t family = tor_addr_family(addr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (node) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    tor_addr_t tmp; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    int asked_for_family = tor_addr_parse(&tmp, conn->socks_request->address); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (family == AF_UNSPEC) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      make_reject_all = 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else if (node_exit_policy_is_exact(node, family) && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               asked_for_family != -1 && !conn->chosen_exit_name) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      make_reject_all = 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (make_reject_all) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      log_info(LD_APP, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               "Exitrouter %s seems to be more restrictive than its exit " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               "policy. Not using this router as exit for now.", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               node_describe(node)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      policies_set_node_exitpolicy_to_reject_all(node); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (family != AF_UNSPEC) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    addr_policy_append_reject_addr(&circ->prepend_policy, addr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /** Helper: change the socks_request->address field on conn to the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * dotted-quad representation of <b>new_addr</b>, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * and send an appropriate REMAP event. */ 
			 |