Browse Source

r8822@totoro: nickm | 2006-10-01 16:24:22 -0400
Fix bug 303: reject attempts to use Tor as a one-hop proxy.


svn:r8566

Nick Mathewson 17 years ago
parent
commit
ce72a9914e
8 changed files with 59 additions and 6 deletions
  1. 3 0
      ChangeLog
  2. 9 4
      doc/TODO
  3. 5 0
      doc/tor-spec.txt
  4. 2 0
      src/or/circuitbuild.c
  5. 15 0
      src/or/circuitlist.c
  6. 9 0
      src/or/connection_edge.c
  7. 10 0
      src/or/control.c
  8. 6 2
      src/or/or.h

+ 3 - 0
ChangeLog

@@ -55,6 +55,9 @@ Changes in version 0.1.2.2-alpha - 2006-10-??
     - Fix NetBSD bug that could allow someone to force uninitialized RAM
       to be sent to a server's DNS resolver. This only affects NetBSD
       and other platforms that do not bounds-check tolower().
+    - Reject (most) attempts to use Tor as a one-hop proxy; if many people
+      start using Tor as a one-hop proxy, exit nodes become a more attractive
+      target for compromise. (Fixes bug 303.)
 
   o Major bugfixes:
     - Avoiding crashing on race condition in dns.c:

+ 9 - 4
doc/TODO

@@ -41,15 +41,17 @@ N - Bug 200: disprefer exit nodes for entry, middle.
     - If 2/3 support port X, weight exits 1/2; weight non-exits 1.
     - (Exit fraction - 1/3):Non-exit fraction
     - (e - 1/3)/(1-e)
-N - Bug 303: block exit from circuits created with create-fast
-    - Specify and document
-    - Implement
-    - Note that we'd like a better speed-bump too.
+  o Bug 303: block exit from circuits created with create-fast
+    o Specify and document
+    o Implement
+    o Note that we'd like a better speed-bump too.
   o Bug 336: CIRC events should have digests when appropriate.
 N - figure out the right thing to do when telling nicknames to
     controllers.  We should always give digest, and possibly sometimes give
     nickname? Or digest, and nickname, with indication of whether name is
     canonical?
+    - edmanm likes $DIGEST~nickname for unNamed routers, and
+      $DIGEST=nickname for Named routers. So do I.
 N - Bug 326: make eventdns thrash less.
 N - Test guard unreachable logic; make sure that we actually attempt to
     connect to guards that we think are unreachable from time to time.
@@ -84,6 +86,7 @@ N . Have (and document) a BEGIN_DIR relay cell that means "Connect to your
     - Use for something, so we can be sure it works.
     - Test and debug
 
+N - Send back RELAY_END cells on malformed RELAY_BEGIN.
 
 x - We should ship with a list of stable dir mirrors -- they're not
     trusted like the authorities, but they'll provide more robustness
@@ -390,6 +393,8 @@ R - Streamline how we pick entry nodes.
 Future version:
   - Configuration format really wants sections.
   - Good RBL substitute.
+  - Our current approach to block attempts to use Tor as a single-hop proxy
+    is pretty lame; we should get a better one.
   . Update the hidden service stuff for the new dir approach.
     - switch to an ascii format, maybe sexpr?
     - authdirservers publish blobs of them.

+ 5 - 0
doc/tor-spec.txt

@@ -410,6 +410,11 @@ TODO:
    [Versions of Tor before 0.1.0.6-rc did not support these cell types;
     clients should not send CREATE_FAST cells to older Tor servers.]
 
+   If an OR sees a circuit created with CREATE_FAST, the OR is sure to be the
+   first hop of a circuit.  ORs SHOULD reject attempts to create streams with
+   RELAY_BEGIN exiting the circuit at the first hop: letting Tor be used as a
+   single hop proxy makes exit nodes a more attractive target for compromise.
+
 5.2. Setting circuit keys
 
    Once the handshake between the OP and an OR is completed, both can

+ 2 - 0
src/or/circuitbuild.c

@@ -925,6 +925,8 @@ onionskin_answer(or_circuit_t *circ, uint8_t cell_type, char *payload,
   else
     memcpy(circ->handshake_digest, cell.payload+DIGEST_LEN, DIGEST_LEN);
 
+  circ->is_first_hop = (cell_type == CELL_CREATED_FAST);
+
   connection_or_write_cell_to_buf(&cell, circ->p_conn);
   log_debug(LD_CIRC,"Finished sending 'created' cell.");
 

+ 15 - 0
src/or/circuitlist.c

@@ -770,6 +770,21 @@ circuit_find_to_cannibalize(uint8_t purpose, extend_info_t *info,
   return best;
 }
 
+/** Return the number of hops in circuit's path. */
+int
+circuit_get_cpath_len(origin_circuit_t *circ)
+{
+  int n = 0;
+  if (circ && circ->cpath) {
+    crypt_path_t *cpath, *cpath_next = NULL;
+    for (cpath = circ->cpath; cpath_next != circ->cpath; cpath = cpath_next) {
+      cpath_next = cpath->next;
+      ++n;
+    }
+  }
+  return n;
+}
+
 /** Go through the circuitlist; mark-for-close each circuit that starts
  *  at us but has not yet been used. */
 void

+ 9 - 0
src/or/connection_edge.c

@@ -1877,6 +1877,15 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
       return 0;
     }
 #endif
+    if (!CIRCUIT_IS_ORIGIN(circ) && TO_OR_CIRCUIT(circ)->is_first_hop) {
+      /* Don't let clients use us as a single-hop proxy; 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. Rejecting.");
+      tor_free(address);
+      return 0;
+    }
   } else if (rh.command == RELAY_COMMAND_BEGIN_DIR) {
     or_options_t *options = get_options();
     address = tor_strdup("127.0.0.1");

+ 10 - 0
src/or/control.c

@@ -1997,6 +1997,16 @@ handle_control_attachstream(control_connection_t *conn, uint32_t len,
                      conn);
     return 0;
   }
+  if (circ && circuit_get_cpath_len(circ) < 2) {
+    if (STATE_IS_V0(conn->_base.state))
+      send_control0_error(conn, ERR_INTERNAL,
+                          "Refuse to attach stream to one-hop circuit.");
+    else
+      connection_write_str_to_buf(
+                     "551 Can't attach stream to one-hop circuit.\r\n",
+                     conn);
+    return 0;
+  }
   if (connection_ap_handshake_rewrite_and_attach(ap_conn, circ) < 0) {
     if (STATE_IS_V0(conn->_base.state))
       send_control0_error(conn, ERR_INTERNAL, "Unable to attach stream.");

+ 6 - 2
src/or/or.h

@@ -1232,8 +1232,6 @@ typedef struct origin_circuit_t {
    * for this circuit. This includes ciphers for each hop,
    * integrity-checking digests for each hop, and package/delivery
    * windows for each hop.
-   *
-   * The cpath field is defined only when we are the circuit's origin.
    */
   crypt_path_t *cpath;
 
@@ -1307,10 +1305,15 @@ typedef struct or_circuit_t {
   /** A hash of location-hidden service's PK if purpose is INTRO_POINT, or a
    * rendezvous cookie if purpose is REND_POINT_WAITING. Filled with zeroes
    * otherwise.
+   * ???? move to a subtype or adjunct structure? Wastes 20 bytes. -NM 
    */
   char rend_token[REND_TOKEN_LEN];
 
+  /* ???? move to a subtype or adjunct structure? Wastes 20 bytes -NM */
   char handshake_digest[DIGEST_LEN]; /**< Stores KH for the handshake. */
+
+  /** True iff this circuit was made with a CREATE_FAST cell. */
+  unsigned int is_first_hop : 1;
 } or_circuit_t;
 
 /** Convert a circuit subtype to a circuit_t.*/
@@ -1751,6 +1754,7 @@ void circuit_mark_all_unused_circs(void);
 void circuit_expire_all_dirty_circs(void);
 void _circuit_mark_for_close(circuit_t *circ, int reason,
                              int line, const char *file);
+int circuit_get_cpath_len(origin_circuit_t *circ);
 
 #define circuit_mark_for_close(c, reason)                               \
   _circuit_mark_for_close((c), (reason), __LINE__, _SHORT_FILE_)