[tor-commits] [tor/master] Server transport proxies should bind on the same port each time, if possible.

nickm at torproject.org nickm at torproject.org
Fri Oct 7 20:03:17 UTC 2011


commit 941709ee50654b9ef59836fadbd8c4e7029c9fc1
Author: George Kadianakis <desnacked at gmail.com>
Date:   Sun Aug 7 18:05:40 2011 +0200

    Server transport proxies should bind on the same port each time, if possible.
---
 src/or/circuitbuild.c |    2 +-
 src/or/config.c       |  235 +++++++++++++++++++++++++++++++++++++++++++-----
 src/or/config.h       |    4 +
 src/or/or.h           |    2 +
 src/or/transports.c   |   78 ++++++++++++-----
 src/or/transports.h   |    4 +-
 6 files changed, 276 insertions(+), 49 deletions(-)

diff --git a/src/or/circuitbuild.c b/src/or/circuitbuild.c
index 3dba83b..fe57070 100644
--- a/src/or/circuitbuild.c
+++ b/src/or/circuitbuild.c
@@ -4610,7 +4610,7 @@ transport_get_by_name(const char *name)
 
   if (!transport_list)
     return NULL;
-  
+
   SMARTLIST_FOREACH_BEGIN(transport_list, const transport_t *, transport) {
     if (!strcmp(transport->name, name))
       return transport;
diff --git a/src/or/config.c b/src/or/config.c
index 02925f3..dced47c 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -473,6 +473,9 @@ static config_var_t _state_vars[] = {
   VAR("EntryGuardAddedBy",       LINELIST_S,  EntryGuards,             NULL),
   V(EntryGuards,                 LINELIST_V,  NULL),
 
+  VAR("TransportProxy",               LINELIST_S, TransportProxies, NULL),
+  V(TransportProxies,                 LINELIST_V, NULL),
+
   V(BWHistoryReadEnds,                ISOTIME,  NULL),
   V(BWHistoryReadInterval,            UINT,     "900"),
   V(BWHistoryReadValues,              CSV,      ""),
@@ -499,7 +502,6 @@ static config_var_t _state_vars[] = {
   V(CircuitBuildAbandonedCount,       UINT,     "0"),
   VAR("CircuitBuildTimeBin",          LINELIST_S, BuildtimeHistogram, NULL),
   VAR("BuildtimeHistogram",           LINELIST_V, BuildtimeHistogram, NULL),
-
   { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }
 };
 
@@ -1212,29 +1214,6 @@ options_act(or_options_t *old_options)
   if (consider_adding_dir_authorities(options, old_options) < 0)
     return -1;
 
-  clear_transport_list();
-  if (options->ClientTransportPlugin) {
-    for (cl = options->ClientTransportPlugin; cl; cl = cl->next) {
-      if (parse_client_transport_line(cl->value, 0)<0) {
-        log_warn(LD_BUG,
-                 "Previously validated ClientTransportPlugin line "
-                 "could not be added!");
-        return -1;
-      }
-    }
-  }
-
-  if (options->ServerTransportPlugin) {
-    for (cl = options->ServerTransportPlugin; cl; cl = cl->next) {
-      if (parse_server_transport_line(cl->value, 0)<0) {
-        log_warn(LD_BUG,
-                 "Previously validated ServerTransportPlugin line "
-                 "could not be added!");
-        return -1;
-      }
-    }
-  }
-
   if (options->Bridges) {
     mark_bridge_list();
     for (cl = options->Bridges; cl; cl = cl->next) {
@@ -1271,6 +1250,30 @@ options_act(or_options_t *old_options)
     rep_hist_load_mtbf_data(time(NULL));
   }
 
+
+  clear_transport_list();
+  if (options->ClientTransportPlugin) {
+    for (cl = options->ClientTransportPlugin; cl; cl = cl->next) {
+      if (parse_client_transport_line(cl->value, 0)<0) {
+        log_warn(LD_BUG,
+                 "Previously validated ClientTransportPlugin line "
+                 "could not be added!");
+        return -1;
+      }
+    }
+  }
+
+  if (options->ServerTransportPlugin) {
+    for (cl = options->ServerTransportPlugin; cl; cl = cl->next) {
+      if (parse_server_transport_line(cl->value, 0)<0) {
+        log_warn(LD_BUG,
+                 "Previously validated ServerTransportPlugin line "
+                 "could not be added!");
+        return -1;
+      }
+    }
+  }
+
   /* Bail out at this point if we're not going to be a client or server:
    * we want to not fork, and to log stuff to stderr. */
   if (!running_tor)
@@ -5465,6 +5468,74 @@ options_get_datadir_fname2_suffix(or_options_t *options,
   return fname;
 }
 
+/** Return true if <b>line</b> is a valid state TransportProxy line.
+ *  Return false otherwise. */
+static int
+state_transport_line_is_valid(char *line)
+{
+  smartlist_t *items = NULL;
+  char *addrport=NULL;
+  tor_addr_t addr;
+  uint16_t port = 0;
+  int r;
+
+  items = smartlist_create();
+  smartlist_split_string(items, line, NULL,
+                         SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
+
+  if (smartlist_len(items) != 2) {
+    log_warn(LD_CONFIG, "state: Not enough arguments in TransportProxy line.");
+    goto err;
+  }
+
+  addrport = smartlist_get(items, 1);
+  if (tor_addr_port_parse(addrport, &addr, &port) < 0) {
+    log_warn(LD_CONFIG, "state: Could not parse addrport.");
+    goto err;
+  }
+
+  if (!port) {
+    log_warn(LD_CONFIG, "state: Transport line did not contain port.");
+    goto err;
+  }
+
+  r = 1;
+  goto done;
+
+ err:
+  r = 0;
+
+ done:
+  SMARTLIST_FOREACH(items, char*, s, tor_free(s));
+  smartlist_free(items);
+  return r;
+}
+
+/** Return 0 if all TransportProxy lines in <b>state</b> are well
+ *  formed. Otherwise, return -1. */
+static int
+validate_transports_in_state(or_state_t *state)
+{
+  int broken = 0;
+
+  config_var_t *var = config_find_option(&state_format,"TransportProxies");
+  if (!var)
+    return 0;
+
+  config_line_t **value = STRUCT_VAR_P(state, var->var_offset);
+  config_line_t *search = NULL;
+
+  for (search = *value ; search ; search = search->next) {
+    if (!state_transport_line_is_valid(search->value)<0)
+      broken = 1;
+  }
+
+  if (broken)
+    log_warn(LD_CONFIG, "state: State file seems to be broken.");
+
+  return 0;
+}
+
 /** Return 0 if every setting in <b>state</b> is reasonable, and a
  * permissible transition from <b>old_state</b>.  Else warn and return -1.
  * Should have no side effects, except for normalizing the contents of
@@ -5483,6 +5554,9 @@ or_state_validate(or_state_t *old_state, or_state_t *state,
   if (entry_guards_parse_state(state, 0, msg)<0)
     return -1;
 
+  if (validate_transports_in_state(state)<0)
+    return -1;
+
   return 0;
 }
 
@@ -5715,6 +5789,118 @@ or_state_save(time_t now)
   return 0;
 }
 
+/** Return the config line for transport <b>transport</b> in the current state.
+ *  Return NULL if there is no config line for <b>transport</b>. */
+static config_line_t *
+get_transport_in_state_by_name(const char *transport)
+{
+  config_var_t *var = config_find_option(&state_format,"TransportProxies");
+  if (!var)
+    return NULL;
+
+  config_line_t **value = STRUCT_VAR_P(get_or_state(), var->var_offset);
+  config_line_t *search = *value;
+
+  while (search) {
+    if (!strcmpstart(search->value, transport))
+      return search;
+
+    search = search->next;
+  }
+  return NULL;
+}
+
+/** Return string containing the address:port part of the
+ *  TransportProxy <b>line</b> for transport <b>transport</b>.  If the
+ *  line is corrupted, return NULL. */
+const char *
+get_transport_bindaddr(const char *line, const char *transport)
+{
+  if (strlen(line) < strlen(transport) + 2)
+    return NULL;
+  else
+    return (line+strlen(transport)+1);
+}
+
+/** Return a string containing the address:port that <b>transport</b>
+ *  should use. */
+const char *
+get_bindaddr_for_transport(const char *transport)
+{
+  static const char default_addrport[] = "127.0.0.1:0";
+  const char *bindaddr = NULL;
+
+  config_line_t *line = get_transport_in_state_by_name(transport);
+  if (!line)
+    return default_addrport;
+
+  bindaddr = get_transport_bindaddr(line->value, transport);
+
+  return bindaddr ? bindaddr : default_addrport;
+}
+
+/** Save <b>transport</b> listening at <b>addr</b>:<b>port</b> to
+ *  state */
+void
+save_transport_to_state(const char *transport,
+                        tor_addr_t *addr, uint16_t port)
+{
+  or_state_t *state = get_or_state();
+
+  char *transport_addrport=NULL;
+
+  /** find where to write on the state */
+  config_line_t **next, *line;
+
+  /* see if this transport is already stored in state */
+  config_line_t *transport_line =
+    get_transport_in_state_by_name(transport);
+
+  if (transport_line) { /* if transport_exists_in_state() */
+    const char *prev_bindaddr = /* get addrport stored in state */
+      get_transport_bindaddr(transport_line->value, transport);
+    tor_asprintf(&transport_addrport, "%s:%d", fmt_addr(addr), (int)port);
+
+    /* if transport in state has the same address as this one, life is good */
+    if (!strcmp(prev_bindaddr, transport_addrport)) {
+      log_warn(LD_CONFIG, "Transport seems to have spawned on its usual address:port.");
+      goto done;
+    } else { /* addrport in state is different than the one we got */
+      log_warn(LD_CONFIG, "Transport seems to have spawned on different address:port."
+                "Let's update the state file with the new address:port");
+      tor_free(transport_line->value); /* free the old line */
+      tor_asprintf(&transport_line->value, "%s %s:%d", transport,
+                   fmt_addr(addr),
+                   (int) port); /* replace old addrport line with new line */
+    }
+  } else { /* never seen this one before; save it in state for next time */
+    log_warn(LD_CONFIG, "It's the first time we see this transport. "
+             "Let's save its address:port");
+    next = &state->TransportProxies;
+    /* find the last TransportProxy line in the state and point 'next'
+       right after it  */
+    line = state->TransportProxies;
+    while (line) {
+      next = &(line->next);
+      line = line->next;
+    }
+
+    /* allocate space for the new line and fill it in */
+    *next = line = tor_malloc_zero(sizeof(config_line_t));
+    line->key = tor_strdup("TransportProxy");
+    tor_asprintf(&line->value, "%s %s:%d", transport,
+                 fmt_addr(addr), (int) port);
+
+    next = &(line->next);
+  }
+
+  if (!get_options()->AvoidDiskWrites)
+    or_state_mark_dirty(state, 0);
+
+ done:
+  tor_free(transport_addrport);
+}
+
 /** Given a file name check to see whether the file exists but has not been
  * modified for a very long time.  If so, remove it. */
 void
@@ -5782,4 +5968,3 @@ getinfo_helper_config(control_connection_t *conn,
   }
   return 0;
 }
-
diff --git a/src/or/config.h b/src/or/config.h
index 49f7e25..dc3a828 100644
--- a/src/or/config.h
+++ b/src/or/config.h
@@ -63,6 +63,10 @@ or_state_t *get_or_state(void);
 int did_last_state_file_write_fail(void);
 int or_state_save(time_t now);
 
+void save_transport_to_state(const char *transport_name,
+                             tor_addr_t *addr, uint16_t port);
+const char * get_bindaddr_for_transport(const char *transport);
+
 int options_need_geoip_info(or_options_t *options, const char **reason_out);
 int getinfo_helper_config(control_connection_t *conn,
                           const char *question, char **answer,
diff --git a/src/or/or.h b/src/or/or.h
index 8bcfc82..d07422f 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -3139,6 +3139,8 @@ typedef struct {
   /** A list of Entry Guard-related configuration lines. */
   config_line_t *EntryGuards;
 
+  config_line_t *TransportProxies;
+
   /** These fields hold information on the history of bandwidth usage for
    * servers.  The "Ends" fields hold the time when we last updated the
    * bandwidth usage. The "Interval" fields hold the granularity, in seconds,
diff --git a/src/or/transports.c b/src/or/transports.c
index 21d76f8..b96792f 100644
--- a/src/or/transports.c
+++ b/src/or/transports.c
@@ -19,10 +19,11 @@ static INLINE int proxy_configuration_finished(managed_proxy_t *mp);
 
 static void managed_proxy_destroy(managed_proxy_t *mp,
                                   int also_free_transports);
-static void register_proxy_transports(managed_proxy_t *mp);
 static void handle_finished_proxy(managed_proxy_t *mp);
 static void configure_proxy(managed_proxy_t *mp);
 
+static void register_server_proxy(managed_proxy_t *mp);
+
 static void parse_method_error(char *line, int is_server_method);
 #define parse_server_method_error(l) parse_method_error(l, 1)
 #define parse_client_method_error(l) parse_method_error(l, 0)
@@ -119,6 +120,7 @@ pt_managed_launch_proxy(const char *method,
   mp->conf_state = PT_PROTO_INFANT;
   mp->stdout = stdout_read;
   mp->transports = smartlist_create();
+  mp->is_server = is_server;
 
   /* register the managed proxy */
   if (!unconfigured_proxy_list)
@@ -179,6 +181,42 @@ configure_proxy(managed_proxy_t *mp)
   }
 }
 
+/** Register server managed proxy <b>mp</b> transports to state */
+static void
+register_server_proxy(managed_proxy_t *mp)
+{
+  if (mp->is_server) {
+    SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) {
+      save_transport_to_state(t->name,&t->addr,t->port); /* pass tor_addr_t? */
+    } SMARTLIST_FOREACH_END(t);
+  }
+}
+
+/** Register all the transports supported by client managed proxy
+ *  <b>mp</b> to the bridge subsystem. */
+static void
+register_client_proxy(managed_proxy_t *mp)
+{
+  SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) {
+    if (transport_add(t)<0) {
+      log_warn(LD_GENERAL, "Could not add transport %s. Skipping.", t->name);
+      transport_free(t);
+    } else {
+      log_warn(LD_GENERAL, "Succesfully registered transport %s", t->name);
+    }
+  } SMARTLIST_FOREACH_END(t);
+}
+
+/** Register the transports of managed proxy <b>mp</b>. */
+static INLINE void
+register_proxy(managed_proxy_t *mp)
+{
+  if (mp->is_server)
+    register_server_proxy(mp);
+  else
+    register_client_proxy(mp);
+}
+
 /** Handle a configured or broken managed proxy <b>mp</b>. */
 static void
 handle_finished_proxy(managed_proxy_t *mp)
@@ -188,7 +226,7 @@ handle_finished_proxy(managed_proxy_t *mp)
     managed_proxy_destroy(mp, 1); /* destroy it and all its transports */
     break;
   case PT_PROTO_CONFIGURED: /* if configured correctly: */
-    register_proxy_transports(mp); /* register all its transports, */
+    register_proxy(mp); /* register transports */
     mp->conf_state = PT_PROTO_COMPLETED; /* mark it as completed, */
     managed_proxy_destroy(mp, 0); /* destroy the managed proxy struct,
                                      keeping the transports intact */
@@ -203,20 +241,6 @@ handle_finished_proxy(managed_proxy_t *mp)
   tor_assert(n_unconfigured_proxies >= 0);
 }
 
-/** Register all the transports supported by managed proxy <b>mp</b>. */
-static void
-register_proxy_transports(managed_proxy_t *mp)
-{
-  SMARTLIST_FOREACH_BEGIN(mp->transports, transport_t *, t) {
-    if (transport_add(t)<0) {
-      log_warn(LD_GENERAL, "Could not add transport %s. Skipping.", t->name);
-      transport_free(t);
-    } else {
-      log_warn(LD_GENERAL, "Succesfully registered transport %s", t->name);
-    }
-  } SMARTLIST_FOREACH_END(t);
-}
-
 /** Free memory allocated by managed proxy <b>mp</b>.
  * If <b>also_free_transports</b> is set, also free the transports
  * associated with this managed proxy. */
@@ -254,8 +278,6 @@ proxy_configuration_finished(managed_proxy_t *mp)
 void
 handle_proxy_line(char *line, managed_proxy_t *mp)
 {
-  log_debug(LD_CONFIG, "Judging line: %s\n", line);
-
   if (strlen(line) < SMALLEST_MANAGED_LINE_SIZE) {
     log_warn(LD_GENERAL, "Managed proxy configuration line is too small. "
              "Discarding");
@@ -401,7 +423,8 @@ parse_method_error(char *line, int is_server)
            line+strlen(error)+1);
 }
 
-/** Parses an SMETHOD <b>line</b>. */
+/** Parses an SMETHOD <b>line</b> and if well-formed it registers the
+ *  new transport in <b>mp</b>. */
 int
 parse_smethod_line(char *line, managed_proxy_t *mp)
 {
@@ -414,6 +437,8 @@ parse_smethod_line(char *line, managed_proxy_t *mp)
   tor_addr_t addr;
   uint16_t port = 0;
 
+  transport_t *transport=NULL;
+
   items = smartlist_create();
   smartlist_split_string(items, line, NULL,
                          SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
@@ -440,6 +465,12 @@ parse_smethod_line(char *line, managed_proxy_t *mp)
     goto err;
   }
 
+  transport = transport_create(&addr, port, method_name, PROXY_NONE);
+  if (!transport)
+    goto err;
+
+  smartlist_add(mp->transports, transport);
+
   /* For now, notify the user so that he knows where the server
      transport is listening. */
   log_warn(LD_CONFIG, "Server transport %s at %s:%d.",
@@ -553,23 +584,26 @@ set_environ(char ***envp, const char *method, int is_server)
   *envp = tor_malloc(sizeof(char*)*(n_envs+1));
   tmp = *envp;
 
+  state_loc = get_datadir_fname("pt_state/");
+
   /* these should all be customizable */
   tor_asprintf(tmp++, "HOME=%s", getenv("HOME"));
   tor_asprintf(tmp++, "PATH=%s", getenv("PATH"));
-  state_loc = get_datadir_fname("pt_state/");
   tor_asprintf(tmp++, "TOR_PT_STATE_LOCATION=%s", state_loc);
-  tor_free(state_loc);
   tor_asprintf(tmp++, "TOR_PT_MANAGED_TRANSPORT_VER=1"); /* temp */
   if (is_server) {
     /* ASN check for ORPort values, should we be here if it's 0? */
     tor_asprintf(tmp++, "TOR_PT_ORPORT=127.0.0.1:%d", options->ORPort); /* temp */
-    tor_asprintf(tmp++, "TOR_PT_SERVER_BINDADDR=127.0.0.1:0");
+    tor_asprintf(tmp++, "TOR_PT_SERVER_BINDADDR=%s",
+                 get_bindaddr_for_transport(method));
     tor_asprintf(tmp++, "TOR_PT_SERVER_TRANSPORTS=%s", method);
     tor_asprintf(tmp++, "TOR_PT_EXTENDED_SERVER_PORT=127.0.0.1:4200"); /* temp*/
   } else {
     tor_asprintf(tmp++, "TOR_PT_CLIENT_TRANSPORTS=%s", method);
   }
   *tmp = NULL;
+
+  tor_free(state_loc);
 }
 
 /* ASN is this too ugly/stupid? */
diff --git a/src/or/transports.h b/src/or/transports.h
index 17a6803..8bd79fe 100644
--- a/src/or/transports.h
+++ b/src/or/transports.h
@@ -40,10 +40,12 @@ typedef struct {
   enum pt_proto_state conf_state; /* the current configuration state */
   int conf_protocol; /* the configuration protocol version used */
 
+  int is_server; /* is it a server proxy? */
+
   FILE *stdout; /* a stream to its stdout
                    (closed in managed_proxy_destroy()) */
 
-  smartlist_t *transports; /* list of transports this proxy spawns */
+  smartlist_t *transports; /* list of transport_t this proxy spawns */
 } managed_proxy_t;
 
 int parse_cmethod_line(char *line, managed_proxy_t *mp);





More information about the tor-commits mailing list