ソースを参照

Add client code to detect attempts to connect to 127.0.0.1 etc

We detect and reject said attempts if there is no chosen exit node or
circuit: connecting to a private addr via a randomly chosen exit node
will usually fail (if all exits reject private addresses), is always
ill-defined (you're not asking for any particular host or service),
and usually an error (you've configured all requests to go over Tor
when you really wanted to configure all _remote_ requests to go over
Tor).

This can also help detect forwarding loop requests.

Found as part of bug2279.
Nick Mathewson 13 年 前
コミット
411ec3c0f8
6 ファイル変更48 行追加1 行削除
  1. 8 0
      changes/bug2279
  2. 5 1
      doc/spec/control-spec.txt
  3. 2 0
      src/or/connection.c
  4. 21 0
      src/or/connection_edge.c
  5. 7 0
      src/or/or.h
  6. 5 0
      src/or/reasons.c

+ 8 - 0
changes/bug2279

@@ -3,3 +3,11 @@
       transparent proxy connection.  Fixes bug 2279.  Bugfix on
       transparent proxy connection.  Fixes bug 2279.  Bugfix on
       Tor 0.1.2.1 alpha.
       Tor 0.1.2.1 alpha.
 
 
+  o Minor features
+    - Detect attempts at the client side to open connections to private
+      IP addresses (like 127.0.0.1, 10.0.0.1, and so on) with a randomly
+      chosen exit node.  Attempts to do so are always ill-defined, generally
+      prevented by exit policies, and usually in error.  This will also
+      help to detect loops in transparent proxy configurations.
+
+

+ 5 - 1
doc/spec/control-spec.txt

@@ -1070,7 +1070,8 @@
       Reason = "MISC" / "RESOLVEFAILED" / "CONNECTREFUSED" /
       Reason = "MISC" / "RESOLVEFAILED" / "CONNECTREFUSED" /
                "EXITPOLICY" / "DESTROY" / "DONE" / "TIMEOUT" /
                "EXITPOLICY" / "DESTROY" / "DONE" / "TIMEOUT" /
                "NOROUTE" / "HIBERNATING" / "INTERNAL"/ "RESOURCELIMIT" /
                "NOROUTE" / "HIBERNATING" / "INTERNAL"/ "RESOURCELIMIT" /
-               "CONNRESET" / "TORPROTOCOL" / "NOTDIRECTORY" / "END"
+               "CONNRESET" / "TORPROTOCOL" / "NOTDIRECTORY" / "END" /
+               "PRIVATE_ADDR"
 
 
    The "REASON" field is provided only for FAILED, CLOSED, and DETACHED
    The "REASON" field is provided only for FAILED, CLOSED, and DETACHED
    events, and only if extended events are enabled (see 3.19).  Clients MUST
    events, and only if extended events are enabled (see 3.19).  Clients MUST
@@ -1079,7 +1080,10 @@
 
 
       END          (We received a RELAY_END cell from the other side of this
       END          (We received a RELAY_END cell from the other side of this
                     stream.)
                     stream.)
+      PRIVATE_ADDR (The client tried to connect to a private address like
+                    127.0.0.1 or 10.0.0.1 over Tor.)
       [XXXX document more. -NM]
       [XXXX document more. -NM]
+      
 
 
    The "REMOTE_REASON" field is provided only when we receive a RELAY_END
    The "REMOTE_REASON" field is provided only when we receive a RELAY_END
    cell, and only if extended events are enabled.  It contains the actual
    cell, and only if extended events are enabled.  It contains the actual

+ 2 - 0
src/or/connection.c

@@ -1205,9 +1205,11 @@ connection_init_accepted_conn(connection_t *conn, uint8_t listener_type)
           conn->state = AP_CONN_STATE_SOCKS_WAIT;
           conn->state = AP_CONN_STATE_SOCKS_WAIT;
           break;
           break;
         case CONN_TYPE_AP_TRANS_LISTENER:
         case CONN_TYPE_AP_TRANS_LISTENER:
+          TO_EDGE_CONN(conn)->is_transparent_ap = 1;
           conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
           conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
           return connection_ap_process_transparent(TO_EDGE_CONN(conn));
           return connection_ap_process_transparent(TO_EDGE_CONN(conn));
         case CONN_TYPE_AP_NATD_LISTENER:
         case CONN_TYPE_AP_NATD_LISTENER:
+          TO_EDGE_CONN(conn)->is_transparent_ap = 1;
           conn->state = AP_CONN_STATE_NATD_WAIT;
           conn->state = AP_CONN_STATE_NATD_WAIT;
           break;
           break;
       }
       }

+ 21 - 0
src/or/connection_edge.c

@@ -1659,6 +1659,27 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
         connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
         connection_mark_unattached_ap(conn, END_STREAM_REASON_TORPROTOCOL);
         return -1;
         return -1;
       }
       }
+      if (!conn->use_begindir && !conn->chosen_exit_name && !circ) {
+        tor_addr_t addr;
+        if (tor_addr_from_str(&addr, socks->address) >= 0 &&
+            tor_addr_is_internal(&addr, 0)) {
+          /* If this is an explicit private address with no chosen exit node,
+           * then we really don't want to try to connect to it.  That's
+           * probably an error. */
+          if (conn->is_transparent_ap) {
+            log_warn(LD_NET,
+                     "Rejecting request for anonymous connection to private "
+                     "address %s on a TransPort or NatdPort.  Possible loop "
+                     "in your NAT rules?", safe_str_client(socks->address));
+          } else {
+            log_warn(LD_NET,
+                     "Rejecting SOCKS request for anonymous connection to "
+                     "private address %s", safe_str_client(socks->address));
+          }
+          connection_mark_unattached_ap(conn, END_STREAM_REASON_PRIVATE_ADDR);
+          return -1;
+        }
+      }
 
 
       if (!conn->use_begindir && !conn->chosen_exit_name && !circ) {
       if (!conn->use_begindir && !conn->chosen_exit_name && !circ) {
         /* see if we can find a suitable enclave exit */
         /* see if we can find a suitable enclave exit */

+ 7 - 0
src/or/or.h

@@ -583,6 +583,9 @@ typedef enum {
 /** This is a connection on the NATD port, and the destination IP:Port was
 /** This is a connection on the NATD port, and the destination IP:Port was
  * either ill-formed or out-of-range. */
  * either ill-formed or out-of-range. */
 #define END_STREAM_REASON_INVALID_NATD_DEST 261
 #define END_STREAM_REASON_INVALID_NATD_DEST 261
+/** The target address is in a private network (like 127.0.0.1 or 10.0.0.1);
+ * you don't want to do that over a randomly chosen exit */
+#define END_STREAM_REASON_PRIVATE_ADDR 262
 
 
 /** Bitwise-and this value with endreason to mask out all flags. */
 /** Bitwise-and this value with endreason to mask out all flags. */
 #define END_STREAM_REASON_MASK 511
 #define END_STREAM_REASON_MASK 511
@@ -1170,6 +1173,10 @@ typedef struct edge_connection_t {
    * zero, abandon the associated mapaddress. */
    * zero, abandon the associated mapaddress. */
   unsigned int chosen_exit_retries:3;
   unsigned int chosen_exit_retries:3;
 
 
+  /** True iff this is an AP connection that came from a transparent or
+   * NATd connection */
+  unsigned int is_transparent_ap:1;
+
   /** If this is a DNSPort connection, this field holds the pending DNS
   /** If this is a DNSPort connection, this field holds the pending DNS
    * request that we're going to try to answer.  */
    * request that we're going to try to answer.  */
   struct evdns_server_request *dns_server_request;
   struct evdns_server_request *dns_server_request;

+ 5 - 0
src/or/reasons.c

@@ -40,6 +40,8 @@ stream_end_reason_to_control_string(int reason)
     case END_STREAM_REASON_NET_UNREACHABLE: return "NET_UNREACHABLE";
     case END_STREAM_REASON_NET_UNREACHABLE: return "NET_UNREACHABLE";
     case END_STREAM_REASON_SOCKSPROTOCOL: return "SOCKS_PROTOCOL";
     case END_STREAM_REASON_SOCKSPROTOCOL: return "SOCKS_PROTOCOL";
 
 
+    case END_STREAM_REASON_PRIVATE_ADDR: return "PRIVATE_ADDR";
+
     default: return NULL;
     default: return NULL;
   }
   }
 }
 }
@@ -125,6 +127,9 @@ stream_end_reason_to_socks5_response(int reason)
       return SOCKS5_NET_UNREACHABLE;
       return SOCKS5_NET_UNREACHABLE;
     case END_STREAM_REASON_SOCKSPROTOCOL:
     case END_STREAM_REASON_SOCKSPROTOCOL:
       return SOCKS5_GENERAL_ERROR;
       return SOCKS5_GENERAL_ERROR;
+    case END_STREAM_REASON_PRIVATE_ADDR:
+      return SOCKS5_GENERAL_ERROR;
+
     default:
     default:
       log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
       log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
              "Reason for ending (%d) not recognized; "
              "Reason for ending (%d) not recognized; "