|  | @@ -168,7 +168,8 @@ static void add_wildcarded_test_address(const char *address);
 | 
	
		
			
				|  |  |  static int configure_nameservers(int force);
 | 
	
		
			
				|  |  |  static int answer_is_wildcarded(const char *ip);
 | 
	
		
			
				|  |  |  static int dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
 | 
	
		
			
				|  |  | -                            or_circuit_t *oncirc, char **resolved_to_hostname);
 | 
	
		
			
				|  |  | +                            or_circuit_t *oncirc, char **resolved_to_hostname,
 | 
	
		
			
				|  |  | +                            int *made_connection_pending_out);
 | 
	
		
			
				|  |  |  #ifdef DEBUG_DNS_CACHE
 | 
	
		
			
				|  |  |  static void _assert_cache_ok(void);
 | 
	
		
			
				|  |  |  #define assert_cache_ok() _assert_cache_ok()
 | 
	
	
		
			
				|  | @@ -596,10 +597,12 @@ dns_resolve(edge_connection_t *exitconn)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |    or_circuit_t *oncirc = TO_OR_CIRCUIT(exitconn->on_circuit);
 | 
	
		
			
				|  |  |    int is_resolve, r;
 | 
	
		
			
				|  |  | +  int made_connection_pending = 0;
 | 
	
		
			
				|  |  |    char *hostname = NULL;
 | 
	
		
			
				|  |  |    is_resolve = exitconn->_base.purpose == EXIT_PURPOSE_RESOLVE;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  r = dns_resolve_impl(exitconn, is_resolve, oncirc, &hostname);
 | 
	
		
			
				|  |  | +  r = dns_resolve_impl(exitconn, is_resolve, oncirc, &hostname,
 | 
	
		
			
				|  |  | +                       &made_connection_pending);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    switch (r) {
 | 
	
		
			
				|  |  |      case 1:
 | 
	
	
		
			
				|  | @@ -639,16 +642,11 @@ dns_resolve(edge_connection_t *exitconn)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |        dns_cancel_pending_resolve(exitconn->_base.address);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      if (!exitconn->_base.marked_for_close) {
 | 
	
		
			
				|  |  | +      if (!made_connection_pending && !exitconn->_base.marked_for_close) {
 | 
	
		
			
				|  |  | +        /* If we made the connection pending, then we freed it already in
 | 
	
		
			
				|  |  | +         * dns_cancel_pending_resolve().  If we marked it for close, it'll
 | 
	
		
			
				|  |  | +         * get freed from the main loop.  Otherwise, can free it now. */
 | 
	
		
			
				|  |  |          connection_free(TO_CONN(exitconn));
 | 
	
		
			
				|  |  | -        // XXX ... and we just leak exitconn otherwise? -RD
 | 
	
		
			
				|  |  | -        // If it's marked for close, it's on closeable_connection_lst in
 | 
	
		
			
				|  |  | -        // main.c.  If it's on the closeable list, it will get freed from
 | 
	
		
			
				|  |  | -        // main.c. -NM
 | 
	
		
			
				|  |  | -        // "<armadev> If that's true, there are other bugs around, where we
 | 
	
		
			
				|  |  | -        //  don't check if it's marked, and will end up double-freeing."
 | 
	
		
			
				|  |  | -        // On the other hand, I don't know of any actual bugs here, so this
 | 
	
		
			
				|  |  | -        // shouldn't be holding up the rc. -RD
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |        break;
 | 
	
		
			
				|  |  |      default:
 | 
	
	
		
			
				|  | @@ -667,10 +665,15 @@ dns_resolve(edge_connection_t *exitconn)
 | 
	
		
			
				|  |  |   * Return -2 on a transient error. If it's a reverse resolve and it's
 | 
	
		
			
				|  |  |   * successful, sets *<b>hostname_out</b> to a newly allocated string
 | 
	
		
			
				|  |  |   * holding the cached reverse DNS value.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * Set *<b>made_connection_pending_out</b> to true if we have placed
 | 
	
		
			
				|  |  | + * <b>exitconn</b> on the list of pending connections for some resolve; set it
 | 
	
		
			
				|  |  | + * to false otherwise.
 | 
	
		
			
				|  |  |   */
 | 
	
		
			
				|  |  |  static int
 | 
	
		
			
				|  |  |  dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
 | 
	
		
			
				|  |  | -                 or_circuit_t *oncirc, char **hostname_out)
 | 
	
		
			
				|  |  | +                 or_circuit_t *oncirc, char **hostname_out,
 | 
	
		
			
				|  |  | +                 int *made_connection_pending_out)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  |    cached_resolve_t *resolve;
 | 
	
		
			
				|  |  |    cached_resolve_t search;
 | 
	
	
		
			
				|  | @@ -684,6 +687,7 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
 | 
	
		
			
				|  |  |    tor_assert(!SOCKET_OK(exitconn->_base.s));
 | 
	
		
			
				|  |  |    assert_cache_ok();
 | 
	
		
			
				|  |  |    tor_assert(oncirc);
 | 
	
		
			
				|  |  | +  *made_connection_pending_out = 0;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* first check if exitconn->_base.address is an IP. If so, we already
 | 
	
		
			
				|  |  |     * know the answer. */
 | 
	
	
		
			
				|  | @@ -757,6 +761,7 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
 | 
	
		
			
				|  |  |          pending_connection->conn = exitconn;
 | 
	
		
			
				|  |  |          pending_connection->next = resolve->pending_connections;
 | 
	
		
			
				|  |  |          resolve->pending_connections = pending_connection;
 | 
	
		
			
				|  |  | +        *made_connection_pending_out = 1;
 | 
	
		
			
				|  |  |          log_debug(LD_EXIT,"Connection (fd %d) waiting for pending DNS "
 | 
	
		
			
				|  |  |                    "resolve of %s", exitconn->_base.s,
 | 
	
		
			
				|  |  |                    escaped_safe_str(exitconn->_base.address));
 | 
	
	
		
			
				|  | @@ -797,6 +802,7 @@ dns_resolve_impl(edge_connection_t *exitconn, int is_resolve,
 | 
	
		
			
				|  |  |    pending_connection = tor_malloc_zero(sizeof(pending_connection_t));
 | 
	
		
			
				|  |  |    pending_connection->conn = exitconn;
 | 
	
		
			
				|  |  |    resolve->pending_connections = pending_connection;
 | 
	
		
			
				|  |  | +  *made_connection_pending_out = 1;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* Add this resolve to the cache and priority queue. */
 | 
	
		
			
				|  |  |    HT_INSERT(cache_map, &cache_root, resolve);
 |