Przeglądaj źródła

Proposal 152 implementation from Josh Albrecht, with tweaks.

svn:r16983
Nick Mathewson 16 lat temu
rodzic
commit
e147e867be

+ 4 - 0
ChangeLog

@@ -83,6 +83,10 @@ Changes in version 0.2.1.6-alpha - 2008-09-xx
       v2 hidden service descriptors.
       v2 hidden service descriptors.
     - Authorities now serve a /tor/dbg-stability.txt URL to help debug
     - Authorities now serve a /tor/dbg-stability.txt URL to help debug
       WFU and MTBF calculations.
       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:
   o Code simplifications and refactoring:
     - Revise the connection_new functions so that a more typesafe variant
     - 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
         with unrecognized items; the protocols line should be preceded with
         an "opt" until these Tors are obsolete.]
         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
 2.2. Extra-info documents
 
 
    Extra-info documents consist of the following items:
    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:
 Last-Modified:
 Author: Geoff Goodell
 Author: Geoff Goodell
 Created: 13-Jul-2008
 Created: 13-Jul-2008
-Status: Draft
+Status: Closed
 
 
 Overview
 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.
 "middle,rendezvous", and other choices are not advised.
 .LP
 .LP
 .TP
 .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
 \fBBridge \fR\fIIP:ORPort\fR [fingerprint]\fP
 When set along with UseBridges, instructs Tor to use the relay at
 When set along with UseBridges, instructs Tor to use the relay at
 "IP:ORPort" as a "bridge" relaying into the Tor network. If "fingerprint"
 "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.
 leave this unset, and Tor will guess your IP address.
 .LP
 .LP
 .TP
 .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
 \fBAssumeReachable \fR\fB0\fR|\fB1\fR\fP
 This option is used when bootstrapping a new Tor network. If set to 1,
 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
 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();
   connections = get_connection_array();
 
 
+  /* XXXX021 Respect ExcludeSingleHopRelays here. */
+
   /* Count how many connections are waiting for a circuit to be built.
   /* 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.
    * 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;
     consider_exit_family = 1;
   }
   }
 
 
+  /* XXXX021 Respect ExcludeSingleHopRelays here. */
+
   if (!entry_guards)
   if (!entry_guards)
     entry_guards = smartlist_create();
     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(Address,                     STRING,   NULL),
   V(AllowInvalidNodes,           CSV,      "middle,rendezvous"),
   V(AllowInvalidNodes,           CSV,      "middle,rendezvous"),
   V(AllowNonRFC953Hostnames,     BOOL,     "0"),
   V(AllowNonRFC953Hostnames,     BOOL,     "0"),
+  V(AllowSingleHopCircuits,      BOOL,     "0"),
+  V(AllowSingleHopExits,         BOOL,     "0"),
   V(AlternateBridgeAuthority,    LINELIST, NULL),
   V(AlternateBridgeAuthority,    LINELIST, NULL),
   V(AlternateDirAuthority,       LINELIST, NULL),
   V(AlternateDirAuthority,       LINELIST, NULL),
   V(AlternateHSAuthority,        LINELIST, NULL),
   V(AlternateHSAuthority,        LINELIST, NULL),
@@ -198,6 +200,7 @@ static config_var_t _option_vars[] = {
   V(TestingEstimatedDescriptorPropagationTime, INTERVAL, "10 minutes"),
   V(TestingEstimatedDescriptorPropagationTime, INTERVAL, "10 minutes"),
   V(ExcludeNodes,                ROUTERSET, NULL),
   V(ExcludeNodes,                ROUTERSET, NULL),
   V(ExcludeExitNodes,            ROUTERSET, NULL),
   V(ExcludeExitNodes,            ROUTERSET, NULL),
+  V(ExcludeSingleHopRelays,      BOOL,     "1"),
   V(ExitNodes,                   ROUTERSET, NULL),
   V(ExitNodes,                   ROUTERSET, NULL),
   V(ExitPolicy,                  LINELIST, NULL),
   V(ExitPolicy,                  LINELIST, NULL),
   V(ExitPolicyRejectPrivate,     BOOL,     "1"),
   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);
       tor_free(address);
       return 0;
       return 0;
     }
     }
-    if (or_circ && or_circ->is_first_hop) {
+    if (or_circ && or_circ->is_first_hop &&
-      /* Don't let clients use us as a single-hop proxy; it attracts attackers
+        !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.
        * and users who'd be better off with, well, single-hop proxies.
        */
        */
       log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
       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);
                     conn);
     return 0;
     return 0;
   }
   }
+  /* Is this a single hop circuit? */
   if (circ && (circuit_get_cpath_len(circ)<2 || hop==1)) {
   if (circ && (circuit_get_cpath_len(circ)<2 || hop==1)) {
-    connection_write_str_to_buf(
+    routerinfo_t *r = NULL;
-                    "551 Can't attach stream to one-hop circuit.\r\n", conn);
+    char* exit_digest;
-    return 0;
+    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) {
   if (circ && hop>0) {
     /* find this hop in the circuit, and set cpath */
     /* find this hop in the circuit, and set cpath */
     cpath = circuit_get_cpath_hop(circ, hop);
     cpath = circuit_get_cpath_hop(circ, hop);

+ 12 - 0
src/or/or.h

@@ -1357,6 +1357,8 @@ typedef struct {
                                       * dnsworker code. */
                                       * dnsworker code. */
   unsigned int caches_extra_info:1; /**< Whether the router caches and serves
   unsigned int caches_extra_info:1; /**< Whether the router caches and serves
                                      * extrainfo documents. */
                                      * extrainfo documents. */
+  unsigned int allow_single_hop_exits:1;  /**< Whether the router allows
+                                     * single hop exits. */
 
 
   /* local info */
   /* local info */
   unsigned int is_running:1; /**< As far as we know, is this OR currently
   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. */
    * if we are a cache).  For authorities, this is always true. */
   int DownloadExtraInfo;
   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
   /** 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.
    * to an internal address, or that an internal address has a PTR mapping.
    * Helps avoid some cross-site attacks. */
    * 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"
                     "opt extra-info-digest %s\n%s"
                     "onion-key\n%s"
                     "onion-key\n%s"
                     "signing-key\n%s"
                     "signing-key\n%s"
-                    "%s%s%s",
+                    "%s%s%s%s",
     router->nickname,
     router->nickname,
     router->address,
     router->address,
     router->or_port,
     router->or_port,
@@ -1704,7 +1704,8 @@ router_dump_router_to_string(char *s, size_t maxlen, routerinfo_t *router,
     onion_pkey, identity_pkey,
     onion_pkey, identity_pkey,
     family_line,
     family_line,
     we_are_hibernating() ? "opt hibernating 1\n" : "",
     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(family_line);
   tor_free(onion_pkey);
   tor_free(onion_pkey);

+ 10 - 0
src/or/routerlist.c

@@ -1767,6 +1767,16 @@ router_choose_random_node(const char *preferred,
 
 
   excludednodes = smartlist_create();
   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())) {
   if ((r = routerlist_find_my_routerinfo())) {
     smartlist_add(excludednodes, r);
     smartlist_add(excludednodes, r);
     routerlist_add_family(excludednodes, r);
     routerlist_add_family(excludednodes, r);

+ 5 - 0
src/or/routerparse.c

@@ -63,6 +63,7 @@ typedef enum {
   K_EXTRA_INFO_DIGEST,
   K_EXTRA_INFO_DIGEST,
   K_CACHES_EXTRA_INFO,
   K_CACHES_EXTRA_INFO,
   K_HIDDEN_SERVICE_DIR,
   K_HIDDEN_SERVICE_DIR,
+  K_ALLOW_SINGLE_HOP_EXITS,
 
 
   K_DIR_KEY_CERTIFICATE_VERSION,
   K_DIR_KEY_CERTIFICATE_VERSION,
   K_DIR_IDENTITY_KEY,
   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("write-history",       K_WRITE_HISTORY,       ARGS,    NO_OBJ ),
   T01("extra-info-digest",   K_EXTRA_INFO_DIGEST,   GE(1),   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("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("family",              K_FAMILY,              ARGS,    NO_OBJ ),
   T01("caches-extra-info",   K_CACHES_EXTRA_INFO,   NO_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)))
   if ((tok = find_first_by_keyword(tokens, K_CACHES_EXTRA_INFO)))
     router->caches_extra_info = 1;
     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))) {
   if ((tok = find_first_by_keyword(tokens, K_EXTRA_INFO_DIGEST))) {
     tor_assert(tok->n_args >= 1);
     tor_assert(tok->n_args >= 1);
     if (strlen(tok->args[0]) == HEX_DIGEST_LEN) {
     if (strlen(tok->args[0]) == HEX_DIGEST_LEN) {