[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] [tor/release-0.2.2] Merge remote branch 'origin/maint-0.2.1' into maint-0.2.2



commit 54135b72f88e6b2301d80f583dfce8aba5d37b5a
Merge: d6329ed 045e6eb
Author: Nick Mathewson <nickm@xxxxxxxxxxxxxx>
Date:   Fri Jan 7 22:04:40 2011 -0500

    Merge remote branch 'origin/maint-0.2.1' into maint-0.2.2

 changes/bug2328          |    3 ++-
 src/or/connection_edge.c |   23 ++++++++++++++++-------
 2 files changed, 18 insertions(+), 8 deletions(-)

diff --combined src/or/connection_edge.c
index 4ae0ccf,052aa37..73ed9fb
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@@ -10,28 -10,6 +10,28 @@@
   **/
  
  #include "or.h"
 +#include "buffers.h"
 +#include "circuitlist.h"
 +#include "circuituse.h"
 +#include "config.h"
 +#include "connection.h"
 +#include "connection_edge.h"
 +#include "connection_or.h"
 +#include "control.h"
 +#include "dns.h"
 +#include "dnsserv.h"
 +#include "dirserv.h"
 +#include "hibernate.h"
 +#include "main.h"
 +#include "policies.h"
 +#include "reasons.h"
 +#include "relay.h"
 +#include "rendclient.h"
 +#include "rendcommon.h"
 +#include "rendservice.h"
 +#include "rephist.h"
 +#include "router.h"
 +#include "routerlist.h"
  
  #ifdef HAVE_LINUX_TYPES_H
  #include <linux/types.h>
@@@ -147,7 -125,7 +147,7 @@@ connection_edge_process_inbuf(edge_conn
        return 0;
      case AP_CONN_STATE_OPEN:
      case EXIT_CONN_STATE_OPEN:
 -      if (connection_edge_package_raw_inbuf(conn, package_partial) < 0) {
 +      if (connection_edge_package_raw_inbuf(conn, package_partial, NULL) < 0) {
          /* (We already sent an end cell if possible) */
          connection_mark_for_close(TO_CONN(conn));
          return -1;
@@@ -352,13 -330,11 +352,13 @@@ connection_edge_finished_connecting(edg
    tor_assert(conn->state == EXIT_CONN_STATE_CONNECTING);
  
    log_info(LD_EXIT,"Exit connection to %s:%u (%s) established.",
 -           escaped_safe_str(conn->address),conn->port,
 +           escaped_safe_str(conn->address), conn->port,
             safe_str(fmt_addr(&conn->addr)));
  
 +  rep_hist_note_exit_stream_opened(conn->port);
 +
    conn->state = EXIT_CONN_STATE_OPEN;
 -  connection_watch_events(conn, EV_READ); /* stop writing, continue reading */
 +  connection_watch_events(conn, READ_EVENT); /* stop writing, keep reading */
    if (connection_wants_to_flush(conn)) /* in case there are any queued relay
                                          * cells */
      connection_start_writing(conn);
@@@ -399,16 -375,13 +399,16 @@@
  static int
  compute_retry_timeout(edge_connection_t *conn)
  {
 +  int timeout = get_options()->CircuitStreamTimeout;
 +  if (timeout) /* if our config options override the default, use them */
 +    return timeout;
    if (conn->num_socks_retries < 2) /* try 0 and try 1 */
      return 10;
    return 15;
  }
  
  /** Find all general-purpose AP streams waiting for a response that sent their
 - * begin/resolve cell >=15 seconds ago. Detach from their current circuit, and
 + * begin/resolve cell too long ago. Detach from their current circuit, and
   * mark their current circuit as unsuitable for new streams. Then call
   * connection_ap_handshake_attach_circuit() to attach to a new circuit (if
   * available) or launch a new one.
@@@ -450,8 -423,7 +450,8 @@@ connection_ap_expire_beginning(void
          log_fn(severity, LD_APP,
              "Tried for %d seconds to get a connection to %s:%d. "
              "Giving up. (%s)",
 -            seconds_since_born, safe_str(conn->socks_request->address),
 +            seconds_since_born,
 +            safe_str_client(conn->socks_request->address),
              conn->socks_request->port,
              conn_state_to_string(CONN_TYPE_AP, conn->_base.state));
          connection_mark_unattached_ap(conn, END_STREAM_REASON_TIMEOUT);
@@@ -468,7 -440,7 +468,7 @@@
      circ = circuit_get_by_edge_conn(conn);
      if (!circ) { /* it's vanished? */
        log_info(LD_APP,"Conn is waiting (address %s), but lost its circ.",
 -               safe_str(conn->socks_request->address));
 +               safe_str_client(conn->socks_request->address));
        connection_mark_unattached_ap(conn, END_STREAM_REASON_TIMEOUT);
        continue;
      }
@@@ -478,7 -450,7 +478,7 @@@
                 "Rend stream is %d seconds late. Giving up on address"
                 " '%s.onion'.",
                 seconds_idle,
 -               safe_str(conn->socks_request->address));
 +               safe_str_client(conn->socks_request->address));
          connection_edge_end(conn, END_STREAM_REASON_TIMEOUT);
          connection_mark_unattached_ap(conn, END_STREAM_REASON_TIMEOUT);
        }
@@@ -488,8 -460,7 +488,8 @@@
      log_fn(cutoff < 15 ? LOG_INFO : severity, LD_APP,
             "We tried for %d seconds to connect to '%s' using exit '%s'."
             " Retrying on a new circuit.",
 -           seconds_idle, safe_str(conn->socks_request->address),
 +           seconds_idle,
 +           safe_str_client(conn->socks_request->address),
             conn->cpath_layer ?
               conn->cpath_layer->extend_info->nickname : "*unnamed*");
      /* send an end down the circuit */
@@@ -600,14 -571,14 +600,14 @@@ circuit_discard_optional_exit_enclaves(
          !edge_conn->chosen_exit_retries)
        continue;
      r1 = router_get_by_nickname(edge_conn->chosen_exit_name, 0);
 -    r2 = router_get_by_nickname(info->nickname, 0);
 +    r2 = router_get_by_digest(info->identity_digest);
      if (!r1 || !r2 || r1 != r2)
        continue;
      tor_assert(edge_conn->socks_request);
      if (edge_conn->chosen_exit_optional) {
        log_info(LD_APP, "Giving up on enclave exit '%s' for destination %s.",
 -               safe_str(edge_conn->chosen_exit_name),
 -               escaped_safe_str(edge_conn->socks_request->address));
 +               safe_str_client(edge_conn->chosen_exit_name),
 +               escaped_safe_str_client(edge_conn->socks_request->address));
        edge_conn->chosen_exit_optional = 0;
        tor_free(edge_conn->chosen_exit_name); /* clears it */
        /* if this port is dangerous, warn or reject it now that we don't
@@@ -712,11 -683,7 +712,11 @@@ addressmap_init(void
  static void
  addressmap_ent_free(void *_ent)
  {
 -  addressmap_entry_t *ent = _ent;
 +  addressmap_entry_t *ent;
 +  if (!_ent)
 +    return;
 +
 +  ent = _ent;
    tor_free(ent->new_address);
    tor_free(ent);
  }
@@@ -725,11 -692,7 +725,11 @@@
  static void
  addressmap_virtaddress_ent_free(void *_ent)
  {
 -  virtaddress_entry_t *ent = _ent;
 +  virtaddress_entry_t *ent;
 +  if (!_ent)
 +    return;
 +
 +  ent = _ent;
    tor_free(ent->ipv4_address);
    tor_free(ent->hostname_address);
    tor_free(ent);
@@@ -819,11 -782,14 +819,11 @@@ addressmap_clean(time_t now
  void
  addressmap_free_all(void)
  {
 -  if (addressmap) {
 -    strmap_free(addressmap, addressmap_ent_free);
 -    addressmap = NULL;
 -  }
 -  if (virtaddress_reversemap) {
 -    strmap_free(virtaddress_reversemap, addressmap_virtaddress_ent_free);
 -    virtaddress_reversemap = NULL;
 -  }
 +  strmap_free(addressmap, addressmap_ent_free);
 +  addressmap = NULL;
 +
 +  strmap_free(virtaddress_reversemap, addressmap_virtaddress_ent_free);
 +  virtaddress_reversemap = NULL;
  }
  
  /** Look at address, and rewrite it until it doesn't want any
@@@ -850,9 -816,9 +850,9 @@@ addressmap_rewrite(char *address, size_
        return (rewrites > 0); /* done, no rewrite needed */
      }
  
 -    cp = tor_strdup(escaped_safe_str(ent->new_address));
 +    cp = tor_strdup(escaped_safe_str_client(ent->new_address));
      log_info(LD_APP, "Addressmap: rewriting %s to %s",
 -             escaped_safe_str(address), cp);
 +             escaped_safe_str_client(address), cp);
      if (ent->expires > 1 && ent->expires < expires)
        expires = ent->expires;
      tor_free(cp);
@@@ -860,7 -826,7 +860,7 @@@
    }
    log_warn(LD_CONFIG,
             "Loop detected: we've rewritten %s 16 times! Using it as-is.",
 -           escaped_safe_str(address));
 +           escaped_safe_str_client(address));
    /* it's fine to rewrite a rewrite, but don't loop forever */
    if (expires_out)
      *expires_out = TIME_MAX;
@@@ -882,9 -848,9 +882,9 @@@ addressmap_rewrite_reverse(char *addres
    tor_snprintf(s, len, "REVERSE[%s]", address);
    ent = strmap_get(addressmap, s);
    if (ent) {
 -    cp = tor_strdup(escaped_safe_str(ent->new_address));
 +    cp = tor_strdup(escaped_safe_str_client(ent->new_address));
      log_info(LD_APP, "Rewrote reverse lookup %s -> %s",
 -             escaped_safe_str(s), cp);
 +             escaped_safe_str_client(s), cp);
      tor_free(cp);
      strlcpy(address, ent->new_address, maxlen);
      r = 1;
@@@ -946,9 -912,7 +946,9 @@@ addressmap_register(const char *address
      if (expires > 1) {
        log_info(LD_APP,"Temporary addressmap ('%s' to '%s') not performed, "
                 "since it's already mapped to '%s'",
 -      safe_str(address), safe_str(new_address), safe_str(ent->new_address));
 +      safe_str_client(address),
 +      safe_str_client(new_address),
 +      safe_str_client(ent->new_address));
        tor_free(new_address);
        return;
      }
@@@ -967,8 -931,7 +967,8 @@@
    ent->source = source;
  
    log_info(LD_CONFIG, "Addressmap: (re)mapped '%s' to '%s'",
 -           safe_str(address), safe_str(ent->new_address));
 +           safe_str_client(address),
 +           safe_str_client(ent->new_address));
    control_event_address_mapped(address, ent->new_address, expires, NULL);
  }
  
@@@ -988,8 -951,7 +988,8 @@@ client_dns_incr_failures(const char *ad
    if (ent->num_resolve_failures < SHORT_MAX)
      ++ent->num_resolve_failures; /* don't overflow */
    log_info(LD_APP, "Address %s now has %d resolve failures.",
 -           safe_str(address), ent->num_resolve_failures);
 +           safe_str_client(address),
 +           ent->num_resolve_failures);
    return ent->num_resolve_failures;
  }
  
@@@ -1177,6 -1139,18 +1177,18 @@@ address_is_in_virtual_range(const char 
    return 0;
  }
  
+ /** Increment the value of next_virtual_addr; reset it to the start of the
+  * virtual address range if it wraps around.
+  */
+ static INLINE void
+ increment_virtual_addr(void)
+ {
+   ++next_virtual_addr;
+   if (addr_mask_cmp_bits(next_virtual_addr, virtual_addr_network,
+                          virtual_addr_netmask_bits))
+     next_virtual_addr = virtual_addr_network;
+ }
+ 
  /** Return a newly allocated string holding an address of <b>type</b>
   * (one of RESOLVED_TYPE_{IPV4|HOSTNAME}) that has not yet been mapped,
   * and that is very unlikely to be the address of any real host.
@@@ -1206,7 -1180,7 +1218,7 @@@ addressmap_get_virtual_address(int type
        /* Don't hand out any .0 or .255 address. */
        while ((next_virtual_addr & 0xff) == 0 ||
               (next_virtual_addr & 0xff) == 0xff) {
-         ++next_virtual_addr;
+         increment_virtual_addr();
          if (! --available) {
            log_warn(LD_CONFIG, "Ran out of virtual addresses!");
            return NULL;
@@@ -1215,20 -1189,17 +1227,17 @@@
        in.s_addr = htonl(next_virtual_addr);
        tor_inet_ntoa(&in, buf, sizeof(buf));
        if (!strmap_get(addressmap, buf)) {
-         ++next_virtual_addr;
+         increment_virtual_addr();
          break;
        }
  
-       ++next_virtual_addr;
+       increment_virtual_addr();
        --available;
-       log_info(LD_CONFIG, "%d addrs available", (int)available);
+       // log_info(LD_CONFIG, "%d addrs available", (int)available);
        if (! available) {
          log_warn(LD_CONFIG, "Ran out of virtual addresses!");
          return NULL;
        }
-       if (addr_mask_cmp_bits(next_virtual_addr, virtual_addr_network,
-                              virtual_addr_netmask_bits))
-         next_virtual_addr = virtual_addr_network;
      }
      return tor_strdup(buf);
    } else {
@@@ -1276,10 -1247,8 +1285,10 @@@ addressmap_register_virtual_address(in
        log_warn(LD_BUG,
                 "Internal confusion: I thought that '%s' was mapped to by "
                 "'%s', but '%s' really maps to '%s'. This is a harmless bug.",
 -               safe_str(new_address), safe_str(*addrp), safe_str(*addrp),
 -               ent?safe_str(ent->new_address):"(nothing)");
 +               safe_str_client(new_address),
 +               safe_str_client(*addrp),
 +               safe_str_client(*addrp),
 +               ent?safe_str_client(ent->new_address):"(nothing)");
    }
  
    tor_free(*addrp);
@@@ -1307,8 -1276,7 +1316,8 @@@
                             (type == RESOLVED_TYPE_IPV4) ?
                             vent->ipv4_address : vent->hostname_address));
      log_info(LD_APP, "Map from %s to %s okay.",
 -           safe_str(*addrp),safe_str(new_address));
 +             safe_str_client(*addrp),
 +             safe_str_client(new_address));
    }
  #endif
  
@@@ -1423,26 -1391,6 +1432,26 @@@ consider_plaintext_ports(edge_connectio
   * different one? */
  #define TRACKHOSTEXITS_RETRIES 5
  
 +/** Call connection_ap_handshake_rewrite_and_attach() unless a controller
 + *  asked us to leave streams unattached. Return 0 in that case.
 + *
 + *  See connection_ap_handshake_rewrite_and_attach()'s
 + *  documentation for arguments and return value.
 + */
 +int
 +connection_ap_rewrite_and_attach_if_allowed(edge_connection_t *conn,
 +                                            origin_circuit_t *circ,
 +                                            crypt_path_t *cpath)
 +{
 +  or_options_t *options = get_options();
 +
 +  if (options->LeaveStreamsUnattached) {
 +    conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT;
 +    return 0;
 +  }
 +  return connection_ap_handshake_rewrite_and_attach(conn, circ, cpath);
 +}
 +
  /** Connection <b>conn</b> just finished its socks handshake, or the
   * controller asked us to take care of it. If <b>circ</b> is defined,
   * then that's where we'll want to attach it. Otherwise we have to
@@@ -1476,7 -1424,7 +1485,7 @@@ connection_ap_handshake_rewrite_and_att
    tor_strlower(socks->address); /* normalize it */
    strlcpy(orig_address, socks->address, sizeof(orig_address));
    log_debug(LD_APP,"Client asked for %s:%d",
 -            safe_str(socks->address),
 +            safe_str_client(socks->address),
              socks->port);
  
    if (socks->command == SOCKS_COMMAND_RESOLVE &&
@@@ -1498,8 -1446,7 +1507,8 @@@
          return -1;
        }
        log_info(LD_APP, "Automapping %s to %s",
 -               escaped_safe_str(socks->address), safe_str(new_addr));
 +               escaped_safe_str_client(socks->address),
 +               safe_str_client(new_addr));
        strlcpy(socks->address, new_addr, sizeof(socks->address));
      }
    }
@@@ -1556,7 -1503,7 +1565,7 @@@
       * information.
       */
      log_warn(LD_APP,"Missing mapping for virtual address '%s'. Refusing.",
 -             socks->address); /* don't safe_str() this yet. */
 +             safe_str_client(socks->address));
      connection_mark_unattached_ap(conn, END_STREAM_REASON_INTERNAL);
      return -1;
    }
@@@ -1564,12 -1511,11 +1573,12 @@@
    /* Parse the address provided by SOCKS.  Modify it in-place if it
     * specifies a hidden-service (.onion) or particular exit node (.exit).
     */
 -  addresstype = parse_extended_hostname(socks->address);
 +  addresstype = parse_extended_hostname(socks->address,
 +                         remapped_to_exit || options->AllowDotExit);
  
    if (addresstype == BAD_HOSTNAME) {
      log_warn(LD_APP, "Invalid onion hostname %s; rejecting",
 -             safe_str(socks->address));
 +             safe_str_client(socks->address));
      control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s",
                                  escaped(socks->address));
      connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
@@@ -1578,7 -1524,7 +1587,7 @@@
  
    if (addresstype == EXIT_HOSTNAME) {
      /* foo.exit -- modify conn->chosen_exit_node to specify the exit
 -     * node, and conn->address to hold only the address portion.*/
 +     * node, and conn->address to hold only the address portion. */
      char *s = strrchr(socks->address,'.');
      tor_assert(!automap);
      if (s) {
@@@ -1589,7 -1535,7 +1598,7 @@@
          *s = 0;
        } else {
          log_warn(LD_APP,"Malformed exit address '%s.exit'. Refusing.",
 -                 safe_str(socks->address));
 +                 safe_str_client(socks->address));
          control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s",
                                      escaped(socks->address));
          connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
@@@ -1605,7 -1551,7 +1614,7 @@@
        } else {
          log_warn(LD_APP,
                   "Unrecognized server in exit address '%s.exit'. Refusing.",
 -                 safe_str(socks->address));
 +                 safe_str_client(socks->address));
          connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
          return -1;
        }
@@@ -1619,7 -1565,7 +1628,7 @@@
                                    escaped(socks->address));
        log_warn(LD_APP,
                 "Destination '%s' seems to be an invalid hostname. Failing.",
 -               safe_str(socks->address));
 +               safe_str_client(socks->address));
        connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
        return -1;
      }
@@@ -1628,6 -1574,18 +1637,6 @@@
        uint32_t answer;
        struct in_addr in;
        /* Reply to resolves immediately if we can. */
 -      if (strlen(socks->address) > RELAY_PAYLOAD_SIZE) {
 -        log_warn(LD_APP,"Address to be resolved is too large. Failing.");
 -        control_event_client_status(LOG_WARN, "SOCKS_BAD_HOSTNAME HOSTNAME=%s",
 -                                    escaped(socks->address));
 -        connection_ap_handshake_socks_resolved(conn,
 -                                               RESOLVED_TYPE_ERROR_TRANSIENT,
 -                                               0,NULL,-1,TIME_MAX);
 -        connection_mark_unattached_ap(conn,
 -                                END_STREAM_REASON_SOCKSPROTOCOL |
 -                                END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED);
 -        return -1;
 -      }
        if (tor_inet_aton(socks->address, &in)) { /* see if it's an IP already */
          /* leave it in network order */
          answer = in.s_addr;
@@@ -1658,7 -1616,7 +1667,7 @@@
          if (r) {
            log_info(LD_APP,
                     "Redirecting address %s to exit at enclave router %s",
 -                   safe_str(socks->address), r->nickname);
 +                   safe_str_client(socks->address), r->nickname);
            /* use the hex digest, not nickname, in case there are two
               routers with this nickname */
            conn->chosen_exit_name =
@@@ -1722,12 -1680,12 +1731,12 @@@
      strlcpy(conn->rend_data->onion_address, socks->address,
              sizeof(conn->rend_data->onion_address));
      log_info(LD_REND,"Got a hidden service request for ID '%s'",
 -             safe_str(conn->rend_data->onion_address));
 +             safe_str_client(conn->rend_data->onion_address));
      /* see if we already have it cached */
      r = rend_cache_lookup_entry(conn->rend_data->onion_address, -1, &entry);
      if (r<0) {
        log_warn(LD_BUG,"Invalid service name '%s'",
 -               safe_str(conn->rend_data->onion_address));
 +               safe_str_client(conn->rend_data->onion_address));
        connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
        return -1;
      }
@@@ -1749,15 -1707,32 +1758,15 @@@
      if (r==0) {
        conn->_base.state = AP_CONN_STATE_RENDDESC_WAIT;
        log_info(LD_REND, "Unknown descriptor %s. Fetching.",
 -               safe_str(conn->rend_data->onion_address));
 -      /* Fetch both, v0 and v2 rend descriptors in parallel. Use whichever
 -       * arrives first. Exception: When using client authorization, only
 -       * fetch v2 descriptors.*/
 +               safe_str_client(conn->rend_data->onion_address));
        rend_client_refetch_v2_renddesc(conn->rend_data);
 -      if (conn->rend_data->auth_type == REND_NO_AUTH)
 -        rend_client_refetch_renddesc(conn->rend_data->onion_address);
      } else { /* r > 0 */
 -      if (now - entry->received < NUM_SECONDS_BEFORE_HS_REFETCH) {
 -        conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
 -        log_info(LD_REND, "Descriptor is here and fresh enough. Great.");
 -        if (connection_ap_handshake_attach_circuit(conn) < 0) {
 -          if (!conn->_base.marked_for_close)
 -            connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH);
 -          return -1;
 -        }
 -      } else {
 -        conn->_base.state = AP_CONN_STATE_RENDDESC_WAIT;
 -        log_info(LD_REND, "Stale descriptor %s. Re-fetching.",
 -                 safe_str(conn->rend_data->onion_address));
 -        /* Fetch both, v0 and v2 rend descriptors in parallel. Use whichever
 -         * arrives first. Exception: When using client authorization, only
 -         * fetch v2 descriptors.*/
 -        rend_client_refetch_v2_renddesc(conn->rend_data);
 -        if (conn->rend_data->auth_type == REND_NO_AUTH)
 -          rend_client_refetch_renddesc(conn->rend_data->onion_address);
 +      conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
 +      log_info(LD_REND, "Descriptor is here. Great.");
 +      if (connection_ap_handshake_attach_circuit(conn) < 0) {
 +        if (!conn->_base.marked_for_close)
 +          connection_mark_unattached_ap(conn, END_STREAM_REASON_CANT_ATTACH);
 +        return -1;
        }
      }
      return 0;
@@@ -1945,12 -1920,24 +1954,12 @@@ connection_ap_handshake_process_socks(e
      return -1;
    } /* else socks handshake is done, continue processing */
  
 -  if (hostname_is_noconnect_address(socks->address))
 -  {
 -    control_event_stream_status(conn, STREAM_EVENT_NEW, 0);
 -    control_event_stream_status(conn, STREAM_EVENT_CLOSED, 0);
 -    connection_mark_unattached_ap(conn, END_STREAM_REASON_DONE);
 -    return -1;
 -  }
 -
    if (SOCKS_COMMAND_IS_CONNECT(socks->command))
      control_event_stream_status(conn, STREAM_EVENT_NEW, 0);
    else
      control_event_stream_status(conn, STREAM_EVENT_NEW_RESOLVE, 0);
  
 -  if (options->LeaveStreamsUnattached) {
 -    conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT;
 -    return 0;
 -  }
 -  return connection_ap_handshake_rewrite_and_attach(conn, NULL, NULL);
 +  return connection_ap_rewrite_and_attach_if_allowed(conn, NULL, NULL);
  }
  
  /** connection_init_accepted_conn() found a new trans AP conn.
@@@ -1964,6 -1951,7 +1973,6 @@@ in
  connection_ap_process_transparent(edge_connection_t *conn)
  {
    socks_request_t *socks;
 -  or_options_t *options = get_options();
  
    tor_assert(conn);
    tor_assert(conn->_base.type == CONN_TYPE_AP);
@@@ -1987,7 -1975,11 +1996,7 @@@
  
    control_event_stream_status(conn, STREAM_EVENT_NEW, 0);
  
 -  if (options->LeaveStreamsUnattached) {
 -    conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT;
 -    return 0;
 -  }
 -  return connection_ap_handshake_rewrite_and_attach(conn, NULL, NULL);
 +  return connection_ap_rewrite_and_attach_if_allowed(conn, NULL, NULL);
  }
  
  /** connection_edge_process_inbuf() found a conn in state natd_wait. See if
@@@ -2008,6 -2000,7 +2017,6 @@@ connection_ap_process_natd(edge_connect
    size_t tlen = 30;
    int err, port_ok;
    socks_request_t *socks;
 -  or_options_t *options = get_options();
  
    tor_assert(conn);
    tor_assert(conn->_base.type == CONN_TYPE_AP);
@@@ -2023,13 -2016,13 +2032,13 @@@
    if (err == 0)
      return 0;
    if (err < 0) {
 -    log_warn(LD_APP,"Natd handshake failed (DEST too long). Closing");
 +    log_warn(LD_APP,"NATD handshake failed (DEST too long). Closing");
      connection_mark_unattached_ap(conn, END_STREAM_REASON_INVALID_NATD_DEST);
      return -1;
    }
  
    if (strcmpstart(tmp_buf, "[DEST ")) {
 -    log_warn(LD_APP,"Natd handshake was ill-formed; closing. The client "
 +    log_warn(LD_APP,"NATD handshake was ill-formed; closing. The client "
               "said: %s",
               escaped(tmp_buf));
      connection_mark_unattached_ap(conn, END_STREAM_REASON_INVALID_NATD_DEST);
@@@ -2038,7 -2031,7 +2047,7 @@@
  
    daddr = tbuf = &tmp_buf[0] + 6; /* after end of "[DEST " */
    if (!(tbuf = strchr(tbuf, ' '))) {
 -    log_warn(LD_APP,"Natd handshake was ill-formed; closing. The client "
 +    log_warn(LD_APP,"NATD handshake was ill-formed; closing. The client "
               "said: %s",
               escaped(tmp_buf));
      connection_mark_unattached_ap(conn, END_STREAM_REASON_INVALID_NATD_DEST);
@@@ -2052,7 -2045,7 +2061,7 @@@
    socks->port = (uint16_t)
      tor_parse_long(tbuf, 10, 1, 65535, &port_ok, &daddr);
    if (!port_ok) {
 -    log_warn(LD_APP,"Natd handshake failed; port %s is ill-formed or out "
 +    log_warn(LD_APP,"NATD handshake failed; port %s is ill-formed or out "
               "of range.", escaped(tbuf));
      connection_mark_unattached_ap(conn, END_STREAM_REASON_INVALID_NATD_DEST);
      return -1;
@@@ -2063,9 -2056,13 +2072,9 @@@
  
    control_event_stream_status(conn, STREAM_EVENT_NEW, 0);
  
 -  if (options->LeaveStreamsUnattached) {
 -    conn->_base.state = AP_CONN_STATE_CONTROLLER_WAIT;
 -    return 0;
 -  }
    conn->_base.state = AP_CONN_STATE_CIRCUIT_WAIT;
  
 -  return connection_ap_handshake_rewrite_and_attach(conn, NULL, NULL);
 +  return connection_ap_rewrite_and_attach_if_allowed(conn, NULL, NULL);
  }
  
  /** Iterate over the two bytes of stream_id until we get one that is not
@@@ -2078,7 -2075,7 +2087,7 @@@ get_unique_stream_id_by_circ(origin_cir
    streamid_t test_stream_id;
    uint32_t attempts=0;
  
 -again:
 + again:
    test_stream_id = circ->next_stream_id++;
    if (++attempts > 1<<16) {
      /* Make sure we don't loop forever if all stream_id's are used. */
@@@ -2194,7 -2191,7 +2203,7 @@@ connection_ap_handshake_send_resolve(ed
      r = tor_addr_parse_reverse_lookup_name(&addr, a, AF_INET, 1);
      if (r <= 0) {
        log_warn(LD_APP, "Rejecting ill-formed reverse lookup of %s",
 -               safe_str(a));
 +               safe_str_client(a));
        connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
        return -1;
      }
@@@ -2202,7 -2199,7 +2211,7 @@@
      r = tor_addr_to_reverse_lookup_name(inaddr_buf, sizeof(inaddr_buf), &addr);
      if (r < 0) {
        log_warn(LD_BUG, "Couldn't generate reverse lookup hostname of %s",
 -               safe_str(a));
 +               safe_str_client(a));
        connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
        return -1;
      }
@@@ -2212,6 -2209,12 +2221,6 @@@
      tor_assert(payload_len <= (int)sizeof(inaddr_buf));
    }
  
 -  if (payload_len > RELAY_PAYLOAD_SIZE) {
 -    /* This should be impossible: we don't accept addresses this big. */
 -    connection_mark_unattached_ap(ap_conn, END_STREAM_REASON_INTERNAL);
 -    return -1;
 -  }
 -
    log_debug(LD_APP,
              "Sending relay cell to begin stream %d.", ap_conn->stream_id);
  
@@@ -2243,8 -2246,7 +2252,8 @@@ connection_ap_make_link(char *address, 
    edge_connection_t *conn;
  
    log_info(LD_APP,"Making internal %s tunnel to %s:%d ...",
 -           want_onehop ? "direct" : "anonymized" , safe_str(address),port);
 +           want_onehop ? "direct" : "anonymized",
 +           safe_str_client(address), port);
  
    conn = edge_connection_new(CONN_TYPE_AP, AF_INET);
    conn->_base.linked = 1; /* so that we can add it safely below. */
@@@ -2510,7 -2512,6 +2519,7 @@@ connection_exit_begin_conn(cell_t *cell
    char *address=NULL;
    uint16_t port;
    or_circuit_t *or_circ = NULL;
 +  or_options_t *options = get_options();
  
    assert_circuit_ok(circ);
    if (!CIRCUIT_IS_ORIGIN(circ))
@@@ -2525,7 -2526,7 +2534,7 @@@
     * that we have a stream connected to a circuit, and we don't connect to a
     * circuit until we have a pending/successful resolve. */
  
 -  if (!server_mode(get_options()) &&
 +  if (!server_mode(options) &&
        circ->purpose != CIRCUIT_PURPOSE_S_REND_JOINED) {
      log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
             "Relay begin cell at non-server. Closing.");
@@@ -2559,30 -2560,21 +2568,30 @@@
        tor_free(address);
        return 0;
      }
 -    if (or_circ && or_circ->is_first_hop &&
 -        !get_options()->AllowSingleHopExits) {
 +    if (or_circ && or_circ->p_conn && !options->AllowSingleHopExits &&
 +        (or_circ->is_first_hop ||
 +         (!connection_or_digest_is_known_relay(
 +                                       or_circ->p_conn->identity_digest) &&
 +          should_refuse_unknown_exits(options)))) {
        /* Don't let clients use us as a single-hop proxy, unless the user
 -       * has explicitly allowed that in the config.  It attracts attackers
 +       * has explicitly allowed that in the config. It attracts attackers
         * and users who'd be better off with, well, single-hop proxies.
         */
        log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
 -             "Attempt to open a stream on first hop of circuit. Closing.");
 +             "Attempt by %s to open a stream %s. Closing.",
 +             safe_str(or_circ->p_conn->_base.address),
 +             or_circ->is_first_hop ? "on first hop of circuit" :
 +                                     "from unknown relay");
        relay_send_end_cell_from_edge(rh.stream_id, circ,
 -                                    END_STREAM_REASON_TORPROTOCOL, NULL);
 +                                    or_circ->is_first_hop ?
 +                                      END_STREAM_REASON_TORPROTOCOL :
 +                                      END_STREAM_REASON_MISC,
 +                                    NULL);
        tor_free(address);
        return 0;
      }
    } else if (rh.command == RELAY_COMMAND_BEGIN_DIR) {
 -    if (!directory_permits_begindir_requests(get_options()) ||
 +    if (!directory_permits_begindir_requests(options) ||
          circ->purpose != CIRCUIT_PURPOSE_OR) {
        relay_send_end_cell_from_edge(rh.stream_id, circ,
                                      END_STREAM_REASON_NOTDIRECTORY, NULL);
@@@ -2608,11 -2600,6 +2617,11 @@@
  
    log_debug(LD_EXIT,"Creating new exit connection.");
    n_stream = edge_connection_new(CONN_TYPE_EXIT, AF_INET);
 +
 +  /* Remember the tunneled request ID in the new edge connection, so that
 +   * we can measure download times. */
 +  TO_CONN(n_stream)->dirreq_id = circ->dirreq_id;
 +
    n_stream->_base.purpose = EXIT_PURPOSE_CONNECT;
  
    n_stream->stream_id = rh.stream_id;
@@@ -2643,7 -2630,7 +2652,7 @@@
      log_debug(LD_REND,"Finished assigning addr/port");
      n_stream->cpath_layer = origin_circ->cpath->prev; /* link it */
  
 -    /* add it into the linked list of n_streams on this circuit */
 +    /* add it into the linked list of p_streams on this circuit */
      n_stream->next_stream = origin_circ->p_streams;
      n_stream->on_circuit = circ;
      origin_circ->p_streams = n_stream;
@@@ -2670,7 -2657,7 +2679,7 @@@
    if (rh.command == RELAY_COMMAND_BEGIN_DIR) {
      tor_assert(or_circ);
      if (or_circ->p_conn && !tor_addr_is_null(&or_circ->p_conn->real_addr))
 -      tor_addr_assign(&n_stream->_base.addr, &or_circ->p_conn->real_addr);
 +      tor_addr_copy(&n_stream->_base.addr, &or_circ->p_conn->real_addr);
      return connection_exit_connect_dir(n_stream);
    }
  
@@@ -2763,7 -2750,7 +2772,7 @@@ connection_exit_connect(edge_connection
    if (!connection_edge_is_rendezvous_stream(edge_conn) &&
        router_compare_to_my_exit_policy(edge_conn)) {
      log_info(LD_EXIT,"%s:%d failed exit policy. Closing.",
 -             escaped_safe_str(conn->address), conn->port);
 +             escaped_safe_str_client(conn->address), conn->port);
      connection_edge_end(edge_conn, END_STREAM_REASON_EXITPOLICY);
      circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn);
      connection_free(conn);
@@@ -2785,7 -2772,7 +2794,7 @@@
      case 0:
        conn->state = EXIT_CONN_STATE_CONNECTING;
  
 -      connection_watch_events(conn, EV_WRITE | EV_READ);
 +      connection_watch_events(conn, READ_EVENT | WRITE_EVENT);
        /* writable indicates finish;
         * readable/error indicates broken link in windows-land. */
        return;
@@@ -2798,7 -2785,7 +2807,7 @@@
      log_warn(LD_BUG,"newly connected conn had data waiting!");
  //    connection_start_writing(conn);
    }
 -  connection_watch_events(conn, EV_READ);
 +  connection_watch_events(conn, READ_EVENT);
  
    /* also, deliver a 'connected' cell back through the circuit. */
    if (connection_edge_is_rendezvous_stream(edge_conn)) {
@@@ -2845,17 -2832,13 +2854,17 @@@ connection_exit_connect_dir(edge_connec
  
    dirconn = dir_connection_new(AF_INET);
  
 -  tor_addr_assign(&dirconn->_base.addr, &exitconn->_base.addr);
 +  tor_addr_copy(&dirconn->_base.addr, &exitconn->_base.addr);
    dirconn->_base.port = 0;
    dirconn->_base.address = tor_strdup(exitconn->_base.address);
    dirconn->_base.type = CONN_TYPE_DIR;
    dirconn->_base.purpose = DIR_PURPOSE_SERVER;
    dirconn->_base.state = DIR_CONN_STATE_SERVER_COMMAND_WAIT;
  
 +  /* Note that the new dir conn belongs to the same tunneled request as
 +   * the edge conn, so that we can measure download times. */
 +  TO_CONN(dirconn)->dirreq_id = TO_CONN(exitconn)->dirreq_id;
 +
    connection_link_connections(TO_CONN(dirconn), TO_CONN(exitconn));
  
    if (connection_add(TO_CONN(exitconn))<0) {
@@@ -2906,16 -2889,10 +2915,16 @@@ connection_edge_is_rendezvous_stream(ed
   * to exit from it, or 0 if it probably will not allow it.
   * (We might be uncertain if conn's destination address has not yet been
   * resolved.)
 + *
 + * If <b>excluded_means_no</b> is 1 and Exclude*Nodes is set and excludes
 + * this relay, return 0.
   */
  int
 -connection_ap_can_use_exit(edge_connection_t *conn, routerinfo_t *exit)
 +connection_ap_can_use_exit(edge_connection_t *conn, routerinfo_t *exit,
 +                           int excluded_means_no)
  {
 +  or_options_t *options = get_options();
 +
    tor_assert(conn);
    tor_assert(conn->_base.type == CONN_TYPE_AP);
    tor_assert(conn->socks_request);
@@@ -2961,35 -2938,20 +2970,35 @@@
      if (!conn->chosen_exit_name && policy_is_reject_star(exit->exit_policy))
        return 0;
    }
 +  if (options->_ExcludeExitNodesUnion &&
 +      (options->StrictNodes || excluded_means_no) &&
 +      routerset_contains_router(options->_ExcludeExitNodesUnion, exit)) {
 +    /* If we are trying to avoid this node as exit, and we have StrictNodes
 +     * set, then this is not a suitable exit. Refuse it.
 +     *
 +     * If we don't have StrictNodes set, then this function gets called in
 +     * two contexts. First, we've got a circuit open and we want to know
 +     * whether we can use it. In that case, we somehow built this circuit
 +     * despite having the last hop in ExcludeExitNodes, so we should be
 +     * willing to use it. Second, we are evaluating whether this is an
 +     * acceptable exit for a new circuit. In that case, skip it. */
 +    return 0;
 +  }
 +
    return 1;
  }
  
  /** If address is of the form "y.onion" with a well-formed handle y:
   *     Put a NUL after y, lower-case it, and return ONION_HOSTNAME.
   *
 - * If address is of the form "y.exit":
 + * If address is of the form "y.exit" and <b>allowdotexit</b> is true:
   *     Put a NUL after y and return EXIT_HOSTNAME.
   *
   * Otherwise:
   *     Return NORMAL_HOSTNAME and change nothing.
   */
  hostname_type_t
 -parse_extended_hostname(char *address)
 +parse_extended_hostname(char *address, int allowdotexit)
  {
      char *s;
      char query[REND_SERVICE_ID_LEN_BASE32+1];
@@@ -2998,16 -2960,8 +3007,16 @@@
      if (!s)
        return NORMAL_HOSTNAME; /* no dot, thus normal */
      if (!strcmp(s+1,"exit")) {
 -      *s = 0; /* NUL-terminate it */
 -      return EXIT_HOSTNAME; /* .exit */
 +      if (allowdotexit) {
 +        *s = 0; /* NUL-terminate it */
 +        return EXIT_HOSTNAME; /* .exit */
 +      } else {
 +        log_warn(LD_APP, "The \".exit\" notation is disabled in Tor due to "
 +                 "security risks. Set AllowDotExit in your torrc to enable "
 +                 "it.");
 +        /* FFFF send a controller event too to notify Vidalia users */
 +        return BAD_HOSTNAME;
 +      }
      }
      if (strcmp(s+1,"onion"))
        return NORMAL_HOSTNAME; /* neither .exit nor .onion, thus normal */
@@@ -3020,9 -2974,17 +3029,9 @@@
      if (rend_valid_service_id(query)) {
        return ONION_HOSTNAME; /* success */
      }
 -failed:
 + failed:
      /* otherwise, return to previous state and return 0 */
      *s = '.';
      return BAD_HOSTNAME;
  }
  
 -/** Check if the address is of the form "y.noconnect"
 - */
 -int
 -hostname_is_noconnect_address(const char *address)
 -{
 -  return ! strcasecmpend(address, ".noconnect");
 -}
 -