Pārlūkot izejas kodu

New config options WarnPlaintextPorts and RejectPlaintextPorts so
Tor can warn and/or refuse connections to ports commonly used with
vulnerable-plaintext protocols.

We still need to figure out some good defaults for them.


svn:r13198

Roger Dingledine 17 gadi atpakaļ
vecāks
revīzija
ff62154ba3
6 mainītis faili ar 80 papildinājumiem un 3 dzēšanām
  1. 3 0
      ChangeLog
  2. 15 2
      doc/spec/control-spec.txt
  3. 10 0
      src/or/config.c
  4. 36 0
      src/or/connection_edge.c
  5. 10 0
      src/or/or.h
  6. 6 1
      src/or/relay.c

+ 3 - 0
ChangeLog

@@ -6,6 +6,9 @@ Changes in version 0.2.0.18-alpha - 2008-01-??
     - If we've gone 12 hours since our last bandwidth check, and we
     - If we've gone 12 hours since our last bandwidth check, and we
       estimate we have less than 50KB bandwidth capacity but we could
       estimate we have less than 50KB bandwidth capacity but we could
       handle more, do another bandwidth test.
       handle more, do another bandwidth test.
+    - New config options WarnPlaintextPorts and RejectPlaintextPorts so
+      Tor can warn and/or refuse connections to ports commonly used with
+      vulnerable-plaintext protocols.
 
 
   o Minor features:
   o Minor features:
     - Don't answer "/tor/networkstatus-bridges" directory requests if
     - Don't answer "/tor/networkstatus-bridges" directory requests if

+ 15 - 2
doc/spec/control-spec.txt

@@ -1300,9 +1300,22 @@ $Id$
        to do so.}
        to do so.}
        [Note: only REASON=CLOCK_JUMPED is implemented currently.]
        [Note: only REASON=CLOCK_JUMPED is implemented currently.]
 
 
+     DANGEROUS_PORT
+     "PORT=" port
+     "RESULT=" "REJECT" / "WARN"
+       A stream was initiated to a port that's commonly used for
+       vulnerable-plaintext protocols. If the Result is "reject", we
+       refused the connection; whereas if it's "warn", we allowed it.
+
+       {Controllers should warn their users when this occurs, unless they
+       happen to know that the application using Tor is in fact doing so
+       correctly (e.g., because it is part of a distributed bundle). They
+       might also want some sort of interface to let the user configure
+       their RejectPlaintextPorts and WarnPlaintextPorts config options.}
+
      DANGEROUS_SOCKS
      DANGEROUS_SOCKS
-     "PROTOCOL=SOCKS4/SOCKS5"
-     "ADDRESS=IP:port"
+     "PROTOCOL=" "SOCKS4" / "SOCKS5"
+     "ADDRESS=" IP:port
        A connection was made to Tor's SOCKS port using one of the SOCKS
        A connection was made to Tor's SOCKS port using one of the SOCKS
        approaches that doesn't support hostnames -- only raw IP addresses.
        approaches that doesn't support hostnames -- only raw IP addresses.
        If the client application got this address from gethostbyname(),
        If the client application got this address from gethostbyname(),

+ 10 - 0
src/or/config.c

@@ -253,6 +253,7 @@ static config_var_t _option_vars[] = {
   V(RecommendedClientVersions,   LINELIST, NULL),
   V(RecommendedClientVersions,   LINELIST, NULL),
   V(RecommendedServerVersions,   LINELIST, NULL),
   V(RecommendedServerVersions,   LINELIST, NULL),
   V(RedirectExit,                LINELIST, NULL),
   V(RedirectExit,                LINELIST, NULL),
+  V(RejectPlaintextPorts,        CSV,      ""),
   V(RelayBandwidthBurst,         MEMUNIT,  "0"),
   V(RelayBandwidthBurst,         MEMUNIT,  "0"),
   V(RelayBandwidthRate,          MEMUNIT,  "0"),
   V(RelayBandwidthRate,          MEMUNIT,  "0"),
   V(RendExcludeNodes,            STRING,   NULL),
   V(RendExcludeNodes,            STRING,   NULL),
@@ -300,6 +301,7 @@ static config_var_t _option_vars[] = {
   V(V3AuthNIntervalsValid,       UINT,     "3"),
   V(V3AuthNIntervalsValid,       UINT,     "3"),
   VAR("VersioningAuthoritativeDirectory",BOOL,VersioningAuthoritativeDir, "0"),
   VAR("VersioningAuthoritativeDirectory",BOOL,VersioningAuthoritativeDir, "0"),
   V(VirtualAddrNetwork,          STRING,   "127.192.0.0/10"),
   V(VirtualAddrNetwork,          STRING,   "127.192.0.0/10"),
+  V(WarnPlaintextPorts,          CSV,      "23,109,110,143"),
   VAR("__AllDirActionsPrivate",  BOOL,  AllDirActionsPrivate,     "0"),
   VAR("__AllDirActionsPrivate",  BOOL,  AllDirActionsPrivate,     "0"),
   VAR("__DisablePredictedCircuits",BOOL,DisablePredictedCircuits, "0"),
   VAR("__DisablePredictedCircuits",BOOL,DisablePredictedCircuits, "0"),
   VAR("__LeaveStreamsUnattached",BOOL,  LeaveStreamsUnattached,   "0"),
   VAR("__LeaveStreamsUnattached",BOOL,  LeaveStreamsUnattached,   "0"),
@@ -2898,6 +2900,14 @@ options_validate(or_options_t *old_options, or_options_t *options,
   if (validate_ports_csv(options->LongLivedPorts, "LongLivedPorts", msg) < 0)
   if (validate_ports_csv(options->LongLivedPorts, "LongLivedPorts", msg) < 0)
     return -1;
     return -1;
 
 
+  if (validate_ports_csv(options->RejectPlaintextPorts,
+                         "RejectPlaintextPorts", msg) < 0)
+    return -1;
+
+  if (validate_ports_csv(options->WarnPlaintextPorts,
+                         "WarnPlaintextPorts", msg) < 0)
+    return -1;
+
   if (options->FascistFirewall && !options->ReachableAddresses) {
   if (options->FascistFirewall && !options->ReachableAddresses) {
     if (options->FirewallPorts && smartlist_len(options->FirewallPorts)) {
     if (options->FirewallPorts && smartlist_len(options->FirewallPorts)) {
       /* We already have firewall ports set, so migrate them to
       /* We already have firewall ports set, so migrate them to

+ 36 - 0
src/or/connection_edge.c

@@ -32,6 +32,7 @@ static int connection_ap_handshake_process_socks(edge_connection_t *conn);
 static int connection_ap_process_natd(edge_connection_t *conn);
 static int connection_ap_process_natd(edge_connection_t *conn);
 static int connection_exit_connect_dir(edge_connection_t *exitconn);
 static int connection_exit_connect_dir(edge_connection_t *exitconn);
 static int address_is_in_virtual_range(const char *addr);
 static int address_is_in_virtual_range(const char *addr);
+static int consider_plaintext_ports(edge_connection_t *conn, uint16_t port);
 
 
 /** An AP stream has failed/finished. If it hasn't already sent back
 /** An AP stream has failed/finished. If it hasn't already sent back
  * a socks reply, send one now (based on endreason). Also set
  * a socks reply, send one now (based on endreason). Also set
@@ -470,6 +471,7 @@ circuit_discard_optional_exit_enclaves(extend_info_t *info)
   {
   {
     if (conn->marked_for_close ||
     if (conn->marked_for_close ||
         conn->type != CONN_TYPE_AP ||
         conn->type != CONN_TYPE_AP ||
+        conn->state != AP_CONN_STATE_CIRCUIT_WAIT ||
         !conn->chosen_exit_optional)
         !conn->chosen_exit_optional)
       continue;
       continue;
     edge_conn = TO_EDGE_CONN(conn);
     edge_conn = TO_EDGE_CONN(conn);
@@ -482,6 +484,9 @@ circuit_discard_optional_exit_enclaves(extend_info_t *info)
                escaped_safe_str(edge_conn->socks_request->address));
                escaped_safe_str(edge_conn->socks_request->address));
       conn->chosen_exit_optional = 0;
       conn->chosen_exit_optional = 0;
       tor_free(edge_conn->chosen_exit_name); /* clears it */
       tor_free(edge_conn->chosen_exit_name); /* clears it */
+      /* if this port is dangerous, warn or reject it now that we don't
+       * think it'll be using an enclave. */
+      consider_plaintext_ports(edge_conn, edge_conn->socks_request->port);
     }
     }
   });
   });
 }
 }
@@ -1182,6 +1187,32 @@ addressmap_get_mappings(smartlist_t *sl, time_t min_expires,
    }
    }
 }
 }
 
 
+/** Check if <b>conn</b> is using a dangerous port. Then warn and/or
+ * reject depending on our config options. */
+static int
+consider_plaintext_ports(edge_connection_t *conn, uint16_t port)
+{
+  or_options_t *options = get_options();
+  int reject = smartlist_string_num_isin(options->RejectPlaintextPorts, port);
+
+  if (smartlist_string_num_isin(options->WarnPlaintextPorts, port)) {
+    log_warn(LD_APP, "Application request to port %d: this port is "
+             "commonly used for unencrypted protocols. Please make sure "
+             "you don't send anything you would mind the rest of the "
+             "Internet reading!%s", port, reject ? " Closing." : "");
+    control_event_client_status(LOG_WARN, "DANGEROUS_PORT PORT=%d RESULT=%s",
+                                port, reject ? "REJECT" : "WARN");
+  }
+
+  if (reject) {
+    log_info(LD_APP, "Port %d listed in RejectPlaintextPorts. Closing.", port);
+    connection_mark_unattached_ap(conn, END_STREAM_REASON_ENTRYPOLICY);
+    return -1;
+  }
+
+  return 0;
+}
+
 /** Connection <b>conn</b> just finished its socks handshake, or the
 /** 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,
  * 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
  * then that's where we'll want to attach it. Otherwise we have to
@@ -1396,6 +1427,11 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn,
         }
         }
       }
       }
 
 
+      /* warn or reject if it's using a dangerous port */
+      if (!conn->use_begindir && !conn->chosen_exit_name && !circ)
+        if (consider_plaintext_ports(conn, socks->port) < 0)
+          return -1;
+
       if (!conn->use_begindir) {
       if (!conn->use_begindir) {
         /* help predict this next time */
         /* help predict this next time */
         rep_hist_note_used_port(socks->port, time(NULL));
         rep_hist_note_used_port(socks->port, time(NULL));

+ 10 - 0
src/or/or.h

@@ -529,6 +529,7 @@ typedef enum {
 #define END_STREAM_REASON_CONNRESET 12
 #define END_STREAM_REASON_CONNRESET 12
 #define END_STREAM_REASON_TORPROTOCOL 13
 #define END_STREAM_REASON_TORPROTOCOL 13
 #define END_STREAM_REASON_NOTDIRECTORY 14
 #define END_STREAM_REASON_NOTDIRECTORY 14
+#define END_STREAM_REASON_ENTRYPOLICY 15
 
 
 /* These high-numbered end reasons are not part of the official spec,
 /* These high-numbered end reasons are not part of the official spec,
  * and are not intended to be put in relay end cells. They are here
  * and are not intended to be put in relay end cells. They are here
@@ -2132,6 +2133,15 @@ typedef struct {
   /** Application ports that require all nodes in circ to have sufficient
   /** Application ports that require all nodes in circ to have sufficient
    * uptime. */
    * uptime. */
   smartlist_t *LongLivedPorts;
   smartlist_t *LongLivedPorts;
+  /** Application ports that are likely to be unencrypted and
+   * unauthenticated; we reject requests for them to prevent the
+   * user from screwing up and leaking plaintext secrets to an
+   * observer somewhere on the Internet. */
+  smartlist_t *RejectPlaintextPorts;
+  /** Related to RejectPlaintextPorts above, except this config option
+   * controls whether we warn (in the log and via a controller status
+   * event) every time a risky connection is attempted. */
+  smartlist_t *WarnPlaintextPorts;
   /** Should we try to reuse the same exit node for a given host */
   /** Should we try to reuse the same exit node for a given host */
   smartlist_t *TrackHostExits;
   smartlist_t *TrackHostExits;
   int TrackHostExitsExpire; /**< Number of seconds until we expire an
   int TrackHostExitsExpire; /**< Number of seconds until we expire an

+ 6 - 1
src/or/relay.c

@@ -600,7 +600,10 @@ connection_edge_end_reason_str(int reason)
 
 
 /** Translate <b>reason</b> (as from a relay 'end' cell) into an
 /** Translate <b>reason</b> (as from a relay 'end' cell) into an
  * appropriate SOCKS5 reply code.
  * appropriate SOCKS5 reply code.
- * DODCDOC 0
+ *
+ * A reason of 0 means that we're not actually expecting to send
+ * this code back to the socks client; we just call it 'succeeded'
+ * to keep things simple.
  */
  */
 socks5_reply_status_t
 socks5_reply_status_t
 connection_edge_end_reason_socks5_response(int reason)
 connection_edge_end_reason_socks5_response(int reason)
@@ -614,6 +617,8 @@ connection_edge_end_reason_socks5_response(int reason)
       return SOCKS5_HOST_UNREACHABLE;
       return SOCKS5_HOST_UNREACHABLE;
     case END_STREAM_REASON_CONNECTREFUSED:
     case END_STREAM_REASON_CONNECTREFUSED:
       return SOCKS5_CONNECTION_REFUSED;
       return SOCKS5_CONNECTION_REFUSED;
+    case END_STREAM_REASON_ENTRYPOLICY:
+      return SOCKS5_NOT_ALLOWED;
     case END_STREAM_REASON_EXITPOLICY:
     case END_STREAM_REASON_EXITPOLICY:
       return SOCKS5_NOT_ALLOWED;
       return SOCKS5_NOT_ALLOWED;
     case END_STREAM_REASON_DESTROY:
     case END_STREAM_REASON_DESTROY: