Option to reuse same exit node?

Mike Perry mikepery at fscked.org
Mon Jan 17 10:13:25 UTC 2005


Thus spake Echo Nolan (hellish at comcast.net):

> Mike Perry wrote:
> | Or is there a reason why this option should not exist?
> It removes anonymity and replaces it with pseudonymity. If this becomes
> available it should be optional. Write the patch, but try and think of a
> way for it to be optional based on site and easily configurable.

I dunno about based on site... I made it an all or nothing config
variable: TrackHostExits. The patch also updates the tor manpage to
describe the option.

It is my opinion that this option isn't THAT harmful, since all it
really enables is the ability to track a user through a given site. A
determined web app can do this merely by setting a unique random
cookie on every browser that connects, removing any protection you
might think you gain from a random IP for each TCP connection.  Many
sites already do this to track users across DHCP sessions for
marketing info.

If desired, I could make the option only work for certain ports that
the user specifies. I suppose it really is only relevant to ports 80
and 443. Let me know if this is desired. If you put up a good argument
for making the config option take hostnames instead (and it is easy to
code), maybe I'll hack that up as well.


Attached are patches against both CVS and 0.0.9.2. I've tested it to
the point of recycling through the array a couple times. Seems to work
for me.


-- 
Mike Perry
Mad Computer Scientist
fscked.org evil labs
-------------- next part --------------
diff -ur tor-0.0.9.2/doc/tor.1.in tor-0.0.9.2-MP/doc/tor.1.in
--- tor-0.0.9.2/doc/tor.1.in	2004-12-11 08:13:15.000000000 -0800
+++ tor-0.0.9.2-MP/doc/tor.1.in	2005-01-17 01:46:49.259729000 -0800
@@ -151,6 +151,15 @@
 If 1, Tor will never use any nodes besides those listed in "entrynodes" for
 the first hop of a circuit.
 .TP
+\fBTrackHostExits \fR\fB0\fR|\fB1\fR\fP
+If 1, Tor will track the 1024 recent connections and attempt to
+reuse the same exit node for each. This is useful if you frequently connect to
+sites that will expire all your authentication cookies (ie log you out) if
+your IP address changes. Note that this option does have the disadvantage of
+making it more clear that a given history is
+associated with a single user. However, most people who would wish to observe
+this will observe it through cookies or other protocol-specific means anyhow.
+.TP
 \fBFascistFirewall \fR\fB0\fR|\fB1\fR\fP
 If 1, Tor will only create outgoing connections to ORs running on ports that
 your firewall allows (defaults to 80 and 443; see \fBFirewallPorts\fR).  This will
diff -ur tor-0.0.9.2/src/or/circuituse.c tor-0.0.9.2-MP/src/or/circuituse.c
--- tor-0.0.9.2/src/or/circuituse.c	2004-12-12 16:44:38.000000000 -0800
+++ tor-0.0.9.2-MP/src/or/circuituse.c	2005-01-17 01:54:08.163020479 -0800
@@ -17,6 +17,10 @@
 
 /********* START VARIABLES **********/
 
+
+exit_history_pair_t exit_history[EXIT_HISTORY_LENGTH]; /* 8k */
+static int exit_history_current;
+
 extern circuit_t *global_circuitlist; /* from circuitlist.c */
 extern int has_fetched_directory; /* from main.c */
 
@@ -863,8 +867,35 @@
 
     link_apconn_to_circ(conn, circ);
     tor_assert(conn->socks_request);
-    if (conn->socks_request->command == SOCKS_COMMAND_CONNECT)
+    if (conn->socks_request->command == SOCKS_COMMAND_CONNECT) {
+
+      /* If an exit wasn't specifically chosen, save the history for future
+       * use */ 
+      if(!conn->chosen_exit_name && get_options()->TrackHostExits) {
+        /* Add connection to our most recently received */
+        if(exit_history[exit_history_current].exit_nickname != NULL) {
+          tor_assert(exit_history[exit_history_current].bobs_hostname);
+          free(exit_history[exit_history_current].exit_nickname);
+          free(exit_history[exit_history_current].bobs_hostname);
+        }
+
+        /* FIXME: this is likely wrong. Is the chosen_exit_nickname the one
+         * actually being used? or was it just blindly taken from conn? */
+        exit_history[exit_history_current].exit_nickname 
+          = strdup(circ->build_state->chosen_exit_name);
+        exit_history[exit_history_current].bobs_hostname 
+          = strdup(conn->socks_request->address); 
+
+        log_fn(LOG_NOTICE, "Tracking host %s to always connect with exit node %s (history entry %d)",
+            exit_history[exit_history_current].bobs_hostname,
+            exit_history[exit_history_current].exit_nickname,
+            exit_history_current);
+
+        exit_history_current = (exit_history_current+1) % EXIT_HISTORY_LENGTH;
+      }
+
       connection_ap_handshake_send_begin(conn, circ);
+    }
     else
       connection_ap_handshake_send_resolve(conn, circ);
 
diff -ur tor-0.0.9.2/src/or/config.c tor-0.0.9.2-MP/src/or/config.c
--- tor-0.0.9.2/src/or/config.c	2005-01-03 15:22:01.000000000 -0800
+++ tor-0.0.9.2-MP/src/or/config.c	2005-01-17 01:36:41.378507000 -0800
@@ -118,6 +118,7 @@
   VAR("StrictEntryNodes",    BOOL,     StrictEntryNodes,     "0"),
   VAR("ExitPolicy",          LINELIST, ExitPolicy,           NULL),
   VAR("ExcludeNodes",        STRING,   ExcludeNodes,         NULL),
+  VAR("TrackHostExits",      BOOL,     TrackHostExits,       "0"),
   VAR("FascistFirewall",     BOOL,     FascistFirewall,      "0"),
   VAR("FirewallPorts",       CSV,      FirewallPorts,        "80,443"),
   VAR("MyFamily",            STRING,   MyFamily,             NULL),
diff -ur tor-0.0.9.2/src/or/connection_edge.c tor-0.0.9.2-MP/src/or/connection_edge.c
--- tor-0.0.9.2/src/or/connection_edge.c	2004-12-24 01:44:45.000000000 -0800
+++ tor-0.0.9.2-MP/src/or/connection_edge.c	2005-01-17 01:56:00.443196306 -0800
@@ -19,6 +19,8 @@
 
 static int connection_ap_handshake_process_socks(connection_t *conn);
 
+extern exit_history_pair_t exit_history[EXIT_HISTORY_LENGTH];
+
 /** There was an EOF. Send an end and mark the connection for close.
  */
 int connection_edge_reached_eof(connection_t *conn) {
@@ -366,6 +368,7 @@
   /* Parse the address provided by SOCKS.  Modify it in-place if it
    * specifies a hidden-service (.onion) or particular exit node (.exit).
    */
+  /* FIXME: What if the address actually has a 46 octet in it?? */
   addresstype = parse_extended_hostname(socks->address);
 
   if (addresstype == EXIT_HOSTNAME) {
@@ -378,10 +381,12 @@
     conn->chosen_exit_name = tor_strdup(s+1);
     *s = 0;
   }
+  
 
   if (addresstype != ONION_HOSTNAME) {
+    int i = 0;
+	
     /* not a hidden-service request (i.e. normal or .exit) */
-
     if (socks->command == SOCKS_COMMAND_RESOLVE) {
       uint32_t answer = 0;
       struct in_addr in;
@@ -409,6 +414,27 @@
       log_fn(LOG_NOTICE,"Application asked to connect to port 0. Refusing.");
       return -1;
     }
+
+    /* Check exit history for a chosen_exit_name */
+    if(get_options()->TrackHostExits) {
+      for(i = 0; i < EXIT_HISTORY_LENGTH; i++) {
+        if(!exit_history[i].bobs_hostname) /* End of the line */
+          break;
+
+        /* If we've connected to this IP before, try to prefer the same exit */
+        if(strcmp(exit_history[i].bobs_hostname, conn->socks_request->address)
+            == 0) {
+          conn->chosen_exit_name = strdup(exit_history[i].exit_nickname);
+
+          log_fn(LOG_NOTICE, 
+              "Reusing cached exit: %s should always connect through exit node %s (history entry %d)",
+              exit_history[i].bobs_hostname,
+              exit_history[i].exit_nickname, i);
+          break;
+        }
+      }
+    }
+
     conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
     rep_hist_note_used_port(socks->port, time(NULL)); /* help predict this next time */
     return connection_ap_handshake_attach_circuit(conn);
diff -ur tor-0.0.9.2/src/or/or.h tor-0.0.9.2-MP/src/or/or.h
--- tor-0.0.9.2/src/or/or.h	2005-01-03 17:11:08.000000000 -0800
+++ tor-0.0.9.2-MP/src/or/or.h	2005-01-17 01:55:16.377408464 -0800
@@ -478,6 +478,16 @@
 typedef struct buf_t buf_t;
 typedef struct socks_request_t socks_request_t;
 
+#define EXIT_HISTORY_LENGTH                1024
+
+typedef struct 
+{
+  char *bobs_hostname;
+  char *exit_nickname;
+} exit_history_pair_t;
+
+
+
 #define CONNECTION_MAGIC 0x7C3C304Eu
 /** Description of a connection to another host or process, and associated
  * data. */
@@ -928,6 +938,7 @@
   int IgnoreVersion; /**< If true, run no matter what versions of Tor the
                       * directory recommends. */
   int RunAsDaemon; /**< If true, run in the background. (Unix only) */
+  int TrackHostExits; /**< Should we try to reuse the same exit node for a given host */
   int FascistFirewall; /**< Whether to prefer ORs reachable on open ports. */
   smartlist_t *FirewallPorts; /** Which ports our firewall allows. */
   int DirFetchPeriod; /**< How often do we fetch new directories? */
-------------- next part --------------
diff -ur tor/doc/tor.1.in tor-mp/doc/tor.1.in
--- tor/doc/tor.1.in	2005-01-15 15:18:42.000000000 -0800
+++ tor-mp/doc/tor.1.in	2005-01-17 01:56:34.515391452 -0800
@@ -151,6 +151,15 @@
 If 1, Tor will never use any nodes besides those listed in "entrynodes" for
 the first hop of a circuit.
 .TP
+\fBTrackHostExits \fR\fB0\fR|\fB1\fR\fP
+If 1, Tor will track the 1024 recent connections and attempt to
+reuse the same exit node for each. This is useful if you frequently connect to
+sites that will expire all your authentication cookies (ie log you out) if
+your IP address changes. Note that this option does have the disadvantage of
+making it more clear that a given history is
+associated with a single user. However, most people who would wish to observe
+this will observe it through cookies or other protocol-specific means anyhow.
+.TP
 \fBFascistFirewall \fR\fB0\fR|\fB1\fR\fP
 If 1, Tor will only create outgoing connections to ORs running on ports that
 your firewall allows (defaults to 80 and 443; see \fBFirewallPorts\fR).  This will
diff -ur tor/src/or/circuituse.c tor-mp/src/or/circuituse.c
--- tor/src/or/circuituse.c	2005-01-13 12:22:37.000000000 -0800
+++ tor-mp/src/or/circuituse.c	2005-01-17 01:56:34.517391170 -0800
@@ -17,6 +17,10 @@
 
 /********* START VARIABLES **********/
 
+
+exit_history_pair_t exit_history[EXIT_HISTORY_LENGTH]; /* 8k */
+static int exit_history_current;
+
 extern circuit_t *global_circuitlist; /* from circuitlist.c */
 extern int has_fetched_directory; /* from main.c */
 
@@ -893,8 +897,35 @@
 
     link_apconn_to_circ(conn, circ);
     tor_assert(conn->socks_request);
-    if (conn->socks_request->command == SOCKS_COMMAND_CONNECT)
+    if (conn->socks_request->command == SOCKS_COMMAND_CONNECT) {
+
+      /* If an exit wasn't specifically chosen, save the history for future
+       * use */ 
+      if(!conn->chosen_exit_name && get_options()->TrackHostExits) {
+        /* Add connection to our most recently received */
+        if(exit_history[exit_history_current].exit_nickname != NULL) {
+          tor_assert(exit_history[exit_history_current].bobs_hostname);
+          free(exit_history[exit_history_current].exit_nickname);
+          free(exit_history[exit_history_current].bobs_hostname);
+        }
+
+        /* FIXME: this is likely wrong. Is the chosen_exit_nickname the one
+         * actually being used? or was it just blindly taken from conn? */
+        exit_history[exit_history_current].exit_nickname 
+          = strdup(circ->build_state->chosen_exit_name);
+        exit_history[exit_history_current].bobs_hostname 
+          = strdup(conn->socks_request->address); 
+
+        log_fn(LOG_NOTICE, "Tracking host %s to always connect with exit node %s (history entry %d)",
+            exit_history[exit_history_current].bobs_hostname,
+            exit_history[exit_history_current].exit_nickname,
+            exit_history_current);
+
+        exit_history_current = (exit_history_current+1) % EXIT_HISTORY_LENGTH;
+      }
+
       connection_ap_handshake_send_begin(conn, circ);
+    }
     else
       connection_ap_handshake_send_resolve(conn, circ);
 
diff -ur tor/src/or/config.c tor-mp/src/or/config.c
--- tor/src/or/config.c	2005-01-13 13:32:08.000000000 -0800
+++ tor-mp/src/or/config.c	2005-01-17 01:56:34.519390888 -0800
@@ -120,6 +120,7 @@
   VAR("StrictEntryNodes",    BOOL,     StrictEntryNodes,     "0"),
   VAR("ExitPolicy",          LINELIST, ExitPolicy,           NULL),
   VAR("ExcludeNodes",        STRING,   ExcludeNodes,         NULL),
+  VAR("TrackHostExits",      BOOL,     TrackHostExits,       "0"),
   VAR("FascistFirewall",     BOOL,     FascistFirewall,      "0"),
   VAR("FirewallPorts",       CSV,      FirewallPorts,        "80,443"),
   VAR("MyFamily",            STRING,   MyFamily,             NULL),
diff -ur tor/src/or/connection_edge.c tor-mp/src/or/connection_edge.c
--- tor/src/or/connection_edge.c	2005-01-13 12:22:38.000000000 -0800
+++ tor-mp/src/or/connection_edge.c	2005-01-17 01:56:34.521390606 -0800
@@ -19,6 +19,8 @@
 
 static int connection_ap_handshake_process_socks(connection_t *conn);
 
+extern exit_history_pair_t exit_history[EXIT_HISTORY_LENGTH];
+
 /** There was an EOF. Send an end and mark the connection for close.
  */
 int connection_edge_reached_eof(connection_t *conn) {
@@ -366,6 +368,7 @@
   /* Parse the address provided by SOCKS.  Modify it in-place if it
    * specifies a hidden-service (.onion) or particular exit node (.exit).
    */
+  /* FIXME: What if the address actually has a 46 octet in it?? */
   addresstype = parse_extended_hostname(socks->address);
 
   if (addresstype == EXIT_HOSTNAME) {
@@ -378,10 +381,12 @@
     conn->chosen_exit_name = tor_strdup(s+1);
     *s = 0;
   }
+  
 
   if (addresstype != ONION_HOSTNAME) {
+    int i = 0;
+	
     /* not a hidden-service request (i.e. normal or .exit) */
-
     if (socks->command == SOCKS_COMMAND_RESOLVE) {
       uint32_t answer = 0;
       struct in_addr in;
@@ -409,6 +414,27 @@
       log_fn(LOG_NOTICE,"Application asked to connect to port 0. Refusing.");
       return -1;
     }
+
+    /* Check exit history for a chosen_exit_name */
+    if(get_options()->TrackHostExits) {
+      for(i = 0; i < EXIT_HISTORY_LENGTH; i++) {
+        if(!exit_history[i].bobs_hostname) /* End of the line */
+          break;
+
+        /* If we've connected to this IP before, try to prefer the same exit */
+        if(strcmp(exit_history[i].bobs_hostname, conn->socks_request->address)
+            == 0) {
+          conn->chosen_exit_name = strdup(exit_history[i].exit_nickname);
+
+          log_fn(LOG_NOTICE, 
+              "Reusing cached exit: %s should always connect through exit node %s (history entry %d)",
+              exit_history[i].bobs_hostname,
+              exit_history[i].exit_nickname, i);
+          break;
+        }
+      }
+    }
+
     conn->state = AP_CONN_STATE_CIRCUIT_WAIT;
     rep_hist_note_used_port(socks->port, time(NULL)); /* help predict this next time */
     return connection_ap_handshake_attach_circuit(conn);
diff -ur tor/src/or/or.h tor-mp/src/or/or.h
--- tor/src/or/or.h	2005-01-13 12:22:38.000000000 -0800
+++ tor-mp/src/or/or.h	2005-01-17 01:56:34.524390183 -0800
@@ -481,6 +481,16 @@
 typedef struct buf_t buf_t;
 typedef struct socks_request_t socks_request_t;
 
+#define EXIT_HISTORY_LENGTH                1024
+
+typedef struct 
+{
+  char *bobs_hostname;
+  char *exit_nickname;
+} exit_history_pair_t;
+
+
+
 #define CONNECTION_MAGIC 0x7C3C304Eu
 /** Description of a connection to another host or process, and associated
  * data. */
@@ -938,6 +948,7 @@
   int IgnoreVersion; /**< If true, run no matter what versions of Tor the
                       * directory recommends. */
   int RunAsDaemon; /**< If true, run in the background. (Unix only) */
+  int TrackHostExits; /**< Should we try to reuse the same exit node for a given host */
   int FascistFirewall; /**< Whether to prefer ORs reachable on open ports. */
   smartlist_t *FirewallPorts; /**< Which ports our firewall allows (strings). */
   /** Application ports that require all nodes in circ to have sufficient uptime. */


More information about the tor-talk mailing list