Browse Source

Proposal 152 implementation from Josh Albrecht, with tweaks.

svn:r16983
Nick Mathewson 16 years ago
parent
commit
e147e867be

+ 4 - 0
ChangeLog

@@ -83,6 +83,10 @@ Changes in version 0.2.1.6-alpha - 2008-09-xx
       v2 hidden service descriptors.
     - Authorities now serve a /tor/dbg-stability.txt URL to help debug
       WFU and MTBF calculations.
+    - Implement most of Proposal 152: allow specialized servers to permit
+      single-hop circuits, and clients to use those servers to build
+      single-hop circuits when using a specialized controller.  Patch
+      from Josh Albrecht.  Resolves "Bug" 768.
 
   o Code simplifications and refactoring:
     - Revise the connection_new functions so that a more typesafe variant

+ 10 - 0
doc/spec/dir-spec.txt

@@ -591,6 +591,16 @@ $Id$
         with unrecognized items; the protocols line should be preceded with
         an "opt" until these Tors are obsolete.]
 
+   "allow-single-hop-exits"
+
+       [At most one.]
+
+       Present only if the router allows single-hop circuits to make exit
+       connections.  Most Tor servers do not support this: this is
+       included for specialized controllers designed to support perspective
+       access and such.
+
+
 2.2. Extra-info documents
 
    Extra-info documents consist of the following items:

+ 1 - 1
doc/spec/proposals/152-single-hop-circuits.txt

@@ -4,7 +4,7 @@ Version:
 Last-Modified:
 Author: Geoff Goodell
 Created: 13-Jul-2008
-Status: Draft
+Status: Closed
 
 Overview
 

+ 14 - 0
doc/tor.1.in

@@ -387,6 +387,14 @@ can opt to use them in some circuit positions, though. The default is
 "middle,rendezvous", and other choices are not advised.
 .LP
 .TP
+\fBExcludeSingleHopRelays \fR\fB0\fR|\fB1\fR\fP
+This option controls whether circuits built by Tor will include relays with
+the AllowSingleHopExits flag set to true.  If ExcludeSingleHopRelays is set to
+0, these relays will be included.  Note that these relays might be at higher
+risk of being seized or observed, so they are not normally included.
+(Default: 1)
+.LP
+.TP
 \fBBridge \fR\fIIP:ORPort\fR [fingerprint]\fP
 When set along with UseBridges, instructs Tor to use the relay at
 "IP:ORPort" as a "bridge" relaying into the Tor network. If "fingerprint"
@@ -784,6 +792,12 @@ The IP address or fqdn of this server (e.g. moria.mit.edu). You can
 leave this unset, and Tor will guess your IP address.
 .LP
 .TP
+\fBAllowSingleHopExits \fR\fB0\fR|\fB1\fR\fP
+This option controls whether clients can use this server as a single hop 
+proxy.  If set to 1, clients can use this server as an exit even if it is
+the only hop in the circuit.  (Default: 0)
+.LP
+.TP
 \fBAssumeReachable \fR\fB0\fR|\fB1\fR\fP
 This option is used when bootstrapping a new Tor network. If set to 1,
 don't do self-reachability testing; just upload your server descriptor

+ 4 - 0
src/or/circuitbuild.c

@@ -1197,6 +1197,8 @@ choose_good_exit_server_general(routerlist_t *dir, int need_uptime,
 
   connections = get_connection_array();
 
+  /* XXXX021 Respect ExcludeSingleHopRelays here. */
+
   /* Count how many connections are waiting for a circuit to be built.
    * We use this for log messages now, but in the future we may depend on it.
    */
@@ -2458,6 +2460,8 @@ choose_random_entry(cpath_build_state_t *state)
     consider_exit_family = 1;
   }
 
+  /* XXXX021 Respect ExcludeSingleHopRelays here. */
+
   if (!entry_guards)
     entry_guards = smartlist_create();
 

+ 3 - 0
src/or/config.c

@@ -136,6 +136,8 @@ static config_var_t _option_vars[] = {
   V(Address,                     STRING,   NULL),
   V(AllowInvalidNodes,           CSV,      "middle,rendezvous"),
   V(AllowNonRFC953Hostnames,     BOOL,     "0"),
+  V(AllowSingleHopCircuits,      BOOL,     "0"),
+  V(AllowSingleHopExits,         BOOL,     "0"),
   V(AlternateBridgeAuthority,    LINELIST, NULL),
   V(AlternateDirAuthority,       LINELIST, NULL),
   V(AlternateHSAuthority,        LINELIST, NULL),
@@ -198,6 +200,7 @@ static config_var_t _option_vars[] = {
   V(TestingEstimatedDescriptorPropagationTime, INTERVAL, "10 minutes"),
   V(ExcludeNodes,                ROUTERSET, NULL),
   V(ExcludeExitNodes,            ROUTERSET, NULL),
+  V(ExcludeSingleHopRelays,      BOOL,     "1"),
   V(ExitNodes,                   ROUTERSET, NULL),
   V(ExitPolicy,                  LINELIST, NULL),
   V(ExitPolicyRejectPrivate,     BOOL,     "1"),

+ 4 - 2
src/or/connection_edge.c

@@ -2498,8 +2498,10 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
       tor_free(address);
       return 0;
     }
-    if (or_circ && or_circ->is_first_hop) {
-      /* Don't let clients use us as a single-hop proxy; it attracts attackers
+    if (or_circ && or_circ->is_first_hop &&
+        !get_options()->AllowSingleHopExits) {
+      /* Don't let clients use us as a single-hop proxy, unless the user
+       * 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,

+ 18 - 3
src/or/control.c

@@ -2324,11 +2324,26 @@ handle_control_attachstream(control_connection_t *conn, uint32_t len,
                     conn);
     return 0;
   }
+  /* Is this a single hop circuit? */
   if (circ && (circuit_get_cpath_len(circ)<2 || hop==1)) {
-    connection_write_str_to_buf(
-                    "551 Can't attach stream to one-hop circuit.\r\n", conn);
-    return 0;
+    routerinfo_t *r = NULL;
+    char* exit_digest;
+    if (circ->build_state &&
+        circ->build_state->chosen_exit &&
+        circ->build_state->chosen_exit->identity_digest) {
+      exit_digest = circ->build_state->chosen_exit->identity_digest;
+      r = router_get_by_digest(exit_digest);
+    }
+    /* Do both the client and relay allow one-hop exit circuits? */
+    if (!r || !r->allow_single_hop_exits ||
+        !get_options()->AllowSingleHopCircuits) {
+      connection_write_str_to_buf(
+      "551 Can't attach stream to this one-hop circuit.\r\n", conn);
+      return 0;
+    }
+    ap_conn->chosen_exit_name = tor_strdup(hex_str(exit_digest, DIGEST_LEN));
   }
+
   if (circ && hop>0) {
     /* find this hop in the circuit, and set cpath */
     cpath = circuit_get_cpath_hop(circ, hop);

+ 12 - 0
src/or/or.h

@@ -1357,6 +1357,8 @@ typedef struct {
                                       * dnsworker code. */
   unsigned int caches_extra_info:1; /**< Whether the router caches and serves
                                      * extrainfo documents. */
+  unsigned int allow_single_hop_exits:1;  /**< Whether the router allows
+                                     * single hop exits. */
 
   /* local info */
   unsigned int is_running:1; /**< As far as we know, is this OR currently
@@ -2420,6 +2422,16 @@ typedef struct {
    * if we are a cache).  For authorities, this is always true. */
   int DownloadExtraInfo;
 
+  /** If true, and we are acting as a relay, allow exit circuits even when
+   * we are the first hop of a circuit. */
+  int AllowSingleHopExits;
+  /** If true, don't allow relays with AllowSingleHopExits=1 to be used in
+   * circuits that we build. */
+  int ExcludeSingleHopRelays;
+  /** If true, and the controller tells us to use a one-hop circuit, and the
+   * exit allows it, we use it. */
+  int AllowSingleHopCircuits;
+
   /** If true, do not believe anybody who tells us that a domain resolves
    * to an internal address, or that an internal address has a PTR mapping.
    * Helps avoid some cross-site attacks. */

+ 3 - 2
src/or/router.c

@@ -1687,7 +1687,7 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
                     "opt extra-info-digest %s\n%s"
                     "onion-key\n%s"
                     "signing-key\n%s"
-                    "%s%s%s",
+                    "%s%s%s%s",
     router->nickname,
     router->address,
     router->or_port,
@@ -1704,7 +1704,8 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
     onion_pkey, identity_pkey,
     family_line,
     we_are_hibernating() ? "opt hibernating 1\n" : "",
-    options->HidServDirectoryV2 ? "opt hidden-service-dir\n" : "");
+    options->HidServDirectoryV2 ? "opt hidden-service-dir\n" : "",
+    options->AllowSingleHopExits ? "opt allow-single-hop-exits\n" : "");
 
   tor_free(family_line);
   tor_free(onion_pkey);

+ 10 - 0
src/or/routerlist.c

@@ -1767,6 +1767,16 @@ router_choose_random_node(const char *preferred,
 
   excludednodes = smartlist_create();
 
+  /* Exclude relays that allow single hop exit circuits, if the user
+   * wants to (such relays might be risky) */
+  if (get_options()->ExcludeSingleHopRelays) {
+    routerlist_t *rl = router_get_routerlist();
+    SMARTLIST_FOREACH(rl->routers, routerinfo_t *, r,
+      if (r->allow_single_hop_exits) {
+        smartlist_add(excludednodes, r);
+      });
+  }
+
   if ((r = routerlist_find_my_routerinfo())) {
     smartlist_add(excludednodes, r);
     routerlist_add_family(excludednodes, r);

+ 5 - 0
src/or/routerparse.c

@@ -63,6 +63,7 @@ typedef enum {
   K_EXTRA_INFO_DIGEST,
   K_CACHES_EXTRA_INFO,
   K_HIDDEN_SERVICE_DIR,
+  K_ALLOW_SINGLE_HOP_EXITS,
 
   K_DIR_KEY_CERTIFICATE_VERSION,
   K_DIR_IDENTITY_KEY,
@@ -239,6 +240,7 @@ static token_rule_t routerdesc_token_table[] = {
   T01("write-history",       K_WRITE_HISTORY,       ARGS,    NO_OBJ ),
   T01("extra-info-digest",   K_EXTRA_INFO_DIGEST,   GE(1),   NO_OBJ ),
   T01("hidden-service-dir",  K_HIDDEN_SERVICE_DIR,  NO_ARGS, NO_OBJ ),
+  T01("allow-single-hop-exits",K_ALLOW_SINGLE_HOP_EXITS,    NO_ARGS, NO_OBJ ),
 
   T01("family",              K_FAMILY,              ARGS,    NO_OBJ ),
   T01("caches-extra-info",   K_CACHES_EXTRA_INFO,   NO_ARGS, NO_OBJ ),
@@ -1363,6 +1365,9 @@ router_parse_entry_from_string(const char *s, const char *end,
   if ((tok = find_first_by_keyword(tokens, K_CACHES_EXTRA_INFO)))
     router->caches_extra_info = 1;
 
+  if ((tok = find_first_by_keyword(tokens, K_ALLOW_SINGLE_HOP_EXITS)))
+    router->allow_single_hop_exits = 1;
+
   if ((tok = find_first_by_keyword(tokens, K_EXTRA_INFO_DIGEST))) {
     tor_assert(tok->n_args >= 1);
     if (strlen(tok->args[0]) == HEX_DIGEST_LEN) {