Reusing Exit Nodes?

Mike Perry mikepery at fscked.org
Sun Jan 30 18:32:24 UTC 2005


Thus spake Roger Dingledine (arma at mit.edu):

> Right. Well, the address mapping data structures should live inside
> Tor, since that's where they're used.
> 
> Speaking of, you might find our string-keyed binary tree handy in keeping
> track of addressmaps and hunting through them, so you don't have to do
> it linearly. Check out strmap_* in src/common/container.c
> 
> > Yeah, once the map address code exists it seems like it would be a
> > replacement for the exit_history data structure, at which point about
> > half my patch should just go away.. But it looks like a sizeable
> > chunk of work though (since it's basically blocked on the entire TC
> > and remote). Is there an ETA? 
> 
> It doesn't have to block on the controller. You could implement it
> locally with normal config options, so people can individually define some
> addressmaps when tor starts, and also so people can define some addresses
> or ports (as your patch already does) that will get auto-addressmapped
> once they pick an exit. Then the controller stuff could come later.
> 
> What do you think? :)

How's this? I kind of just haphazardly placed the addressmap_remap
function close to where I needed it. It turned out to be a much
smaller patch than my previous one.

Do you think this is good enough to use as a starting point for the
full addressmap feature?

-- 
Mike Perry
Mad Computer Scientist
fscked.org evil labs
-------------- next part --------------
diff -ur tor/doc/tor.1.in tor-MP/doc/tor.1.in
--- tor/doc/tor.1.in	2005-01-18 19:46:22.000000000 -0800
+++ tor-MP/doc/tor.1.in	2005-01-27 00:26:18.000000000 -0800
@@ -151,6 +151,23 @@
 If 1, Tor will never use any nodes besides those listed in "entrynodes" for
 the first hop of a circuit.
 .TP
+\fBTrackHostExits \fR\fIhost1\fR,\fI.domain1\fR|\fI.\fR\fP
+For each value in the comma separated list, Tor will track recent connections 
+to hosts that match this value and attempt to
+reuse the same exit node for each. If the value is prepended with a '.', it is
+treated as matching an entire domain. If one of the values is just a '.', it
+means match everything. This option 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
+\fBTrackHostExitsExpire \fR\fINUM\fP
+Since exit servers go up and down, it is desirable to expire the association
+between host and exit server after so many minutes of inactivity. The default
+is 30.
+.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-21 22:33:07.000000000 -0800
+++ tor-MP/src/or/circuituse.c	2005-01-30 01:44:24.000000000 -0800
@@ -955,8 +955,63 @@
 
     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) {
+
+      or_options_t *options = get_options();
+      /* If an exit wasn't specifically chosen, save the history for future
+       * use */
+
+	  /* search the addressmap for this conn's dest.. */
+	  /* If he's not in the address map.. */
+      if(options->TrackHostExits && 
+         (!addressmap || !strmap_get(addressmap, conn->socks_request->address))) {
+        int found_needle = 0;
+        SMARTLIST_FOREACH(options->TrackHostExits, const char *, cp, {
+            if(cp[0] == '.') { /* match end */
+              char *str;
+              if((str = strstr(conn->socks_request->address, &cp[1]))) {
+                if(str == conn->socks_request->address 
+                  || strcmp(str, &cp[1]) == 0) {
+                  found_needle = 1; 
+                }
+              }
+            } else if(strcmp(cp, conn->socks_request->address) == 0) { 
+              found_needle = 1; 
+            }
+        });
+
+        if(found_needle) {
+		  /* Add this exit/hostname pair to the addressmap. */
+  		  time_t now = time(NULL);
+          addressmap_entry_t *ent = (addressmap_entry_t *)malloc(sizeof(addressmap_entry_t));
+          size_t addrlen = strlen(conn->socks_request->address);
+          size_t exitlen = strlen(circ->build_state->chosen_exit_name);
+          
+          ent->address = (char *)malloc(
+              addrlen + 1 /* '.' */ +
+              exitlen + 1 /* '.' */ +
+              strlen("exit") + 1 /* '\0' */);              
+          ent->max_age = options->TrackHostExitsExpire*60;
+          ent->last_used = now;
+
+          strcpy(ent->address, conn->socks_request->address);
+          ent->address[addrlen] = '.';
+          
+          strcpy(&ent->address[addrlen+1], circ->build_state->chosen_exit_name);
+          ent->address[addrlen+exitlen+1] = '.';
+
+          strcpy(&ent->address[addrlen+exitlen+2], "exit");
+
+          if(!addressmap) addressmap = strmap_new();
+
+          strmap_set(addressmap, conn->socks_request->address, ent);
+          log_fn(LOG_NOTICE, "Addressmap: creating %s to %s",
+              conn->socks_request->address, ent->address);
+        }
+      }
+
       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-30 01:40:46.000000000 -0800
+++ tor-MP/src/or/config.c	2005-01-29 20:55:16.000000000 -0800
@@ -120,6 +120,8 @@
   VAR("StrictEntryNodes",    BOOL,     StrictEntryNodes,     "0"),
   VAR("ExitPolicy",          LINELIST, ExitPolicy,           NULL),
   VAR("ExcludeNodes",        STRING,   ExcludeNodes,         NULL),
+  VAR("TrackHostExits",      CSV,      TrackHostExits,       NULL),
+  VAR("TrackHostExitsExpire",UINT,     TrackHostExitsExpire, "30"),
   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-30 01:40:46.000000000 -0800
+++ tor-MP/src/or/connection_edge.c	2005-01-30 01:49:15.000000000 -0800
@@ -320,6 +320,32 @@
   }
 }
 
+strmap_t *addressmap;
+
+void addressmap_remap(socks_request_t *socks) {
+	addressmap_entry_t *ent;
+	
+	if(!addressmap) addressmap = strmap_new();
+   	ent = strmap_get(addressmap, socks->address);
+
+	if(ent) {
+		if(ent->last_used + ent->max_age < time(NULL)) {
+			log_fn(LOG_NOTICE, "Addressmap: expiring %s to %s",
+					socks->address, ent->address);
+
+			free(ent->address);
+			strmap_remove(addressmap, socks->address);
+			free(ent);
+		} else { 
+			log_fn(LOG_NOTICE, "Addressmap: remaping %s to %s",
+					socks->address, ent->address);
+			ent->last_used = time(NULL);
+			strncpy(socks->address, ent->address, sizeof(socks->address)-1);
+			socks->address[sizeof(socks->address)-1] = 0;
+		}
+	}
+}
+
 /** connection_edge_process_inbuf() found a conn in state
  * socks_wait. See if conn->inbuf has the right bytes to proceed with
  * the socks handshake.
@@ -363,6 +389,9 @@
     return sockshere;
   } /* else socks handshake is done, continue processing */
 
+  /* For address map controls, remap the address */
+  addressmap_remap(socks);
+  
   /* Parse the address provided by SOCKS.  Modify it in-place if it
    * specifies a hidden-service (.onion) or particular exit node (.exit).
    */
@@ -381,7 +410,6 @@
 
   if (addresstype != ONION_HOSTNAME) {
     /* not a hidden-service request (i.e. normal or .exit) */
-
     if (socks->command == SOCKS_COMMAND_RESOLVE) {
       uint32_t answer = 0;
       struct in_addr in;
diff -ur tor/src/or/or.h tor-MP/src/or/or.h
--- tor/src/or/or.h	2005-01-30 01:40:46.000000000 -0800
+++ tor-MP/src/or/or.h	2005-01-30 01:42:41.000000000 -0800
@@ -483,6 +483,13 @@
 typedef struct buf_t buf_t;
 typedef struct socks_request_t socks_request_t;
 
+typedef struct {
+	char *address;
+	time_t max_age;
+	time_t last_used;
+} addressmap_entry_t;
+extern strmap_t *addressmap;
+
 #define CONNECTION_MAGIC 0x7C3C304Eu
 /** Description of a connection to another host or process, and associated
  * data. */
@@ -942,6 +949,8 @@
   int IgnoreVersion; /**< If true, run no matter what versions of Tor the
                       * directory recommends. */
   int RunAsDaemon; /**< If true, run in the background. (Unix only) */
+  smartlist_t *TrackHostExits; /**< Should we try to reuse the same exit node for a given host */
+  uint32_t TrackHostExitsExpire; /**< Number of minutes until we expire a connection */
   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