From 3394daa34842a397561e65002a33c13355df651d Mon Sep 17 00:00:00 2001
From: George Kadianakis <desnacked@riseup.net>
Date: Thu, 28 Feb 2013 18:58:36 +0200
Subject: [PATCH 1/4] Only launch transport proxies that provide useful
 transports.

---
 changes/bug5018     |  3 +++
 src/or/config.c     | 20 ++++++++++++++++----
 src/or/entrynodes.c | 23 +++++++++++++++++++++++
 src/or/entrynodes.h |  1 +
 4 files changed, 43 insertions(+), 4 deletions(-)
 create mode 100644 changes/bug5018

diff --git a/changes/bug5018 b/changes/bug5018
new file mode 100644
index 0000000..c5c12ef
--- /dev/null
+++ b/changes/bug5018
@@ -0,0 +1,3 @@
+  o Minor features:
+    - Don't launch pluggable transport proxies that contribute
+      transports we don't need. Resolves ticket 5018.
diff --git a/src/or/config.c b/src/or/config.c
index ef02946..47510c5 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -4242,7 +4242,8 @@ parse_client_transport_line(const char *line, int validate_only)
   int is_managed=0;
   char **proxy_argv=NULL;
   char **tmp=NULL;
-  int proxy_argc,i;
+  int proxy_argc, i;
+  int is_useless_proxy=1;
 
   int line_length;
 
@@ -4264,11 +4265,16 @@ parse_client_transport_line(const char *line, int validate_only)
   smartlist_split_string(transport_list, transports, ",",
                          SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0);
   SMARTLIST_FOREACH_BEGIN(transport_list, const char *, transport_name) {
+    /* validate transport names */
     if (!string_is_C_identifier(transport_name)) {
       log_warn(LD_CONFIG, "Transport name is not a C identifier (%s).",
                transport_name);
       goto err;
     }
+
+    /* see if we actually need the transports provided by this proxy */
+    if (!validate_only && transport_is_needed(transport_name))
+      is_useless_proxy = 0;
   } SMARTLIST_FOREACH_END(transport_name);
 
   /* field2 is either a SOCKS version or "exec" */
@@ -4287,9 +4293,15 @@ parse_client_transport_line(const char *line, int validate_only)
   }
 
   if (is_managed) { /* managed */
-    if (!validate_only) {  /* if we are not just validating, use the
-                             rest of the line as the argv of the proxy
-                             to be launched */
+    if (!validate_only && is_useless_proxy) {
+      log_warn(LD_GENERAL, "Pluggable transport proxy (%s) does not provide "
+               "any needed transports and will not be launched.", line);
+    }
+
+    /* If we are not just validating, use the rest of the line as the
+       argv of the proxy to be launched. Also, make sure that we are
+       only launching proxies that contribute useful transports.  */
+    if (!validate_only && !is_useless_proxy) {
       proxy_argc = line_length-2;
       tor_assert(proxy_argc > 0);
       proxy_argv = tor_malloc_zero(sizeof(char*)*(proxy_argc+1));
diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index 2aa063c..4062cee 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -1773,6 +1773,29 @@ bridge_resolve_conflicts(const tor_addr_t *addr, uint16_t port,
   } SMARTLIST_FOREACH_END(bridge);
 }
 
+/** Return True if we have a bridge that uses a transport with name
+ *  <b>transport_name</b>. */
+int
+transport_is_needed(const char *transport_name)
+{
+  int retval;
+  smartlist_t *needed_transports = NULL;
+
+  if (!bridge_list)
+    return 0;
+
+  needed_transports = smartlist_new();
+
+  SMARTLIST_FOREACH_BEGIN(bridge_list, const bridge_info_t *, bridge) {
+    if (bridge->transport_name)
+      smartlist_add(needed_transports, bridge->transport_name);
+  } SMARTLIST_FOREACH_END(bridge);
+
+  retval = smartlist_string_isin(needed_transports, transport_name);
+  smartlist_free(needed_transports);
+  return retval;
+}
+
 /** Remember a new bridge at <b>addr</b>:<b>port</b>. If <b>digest</b>
  * is set, it tells us the identity key too.  If we already had the
  * bridge in our list, unmark it, and don't actually add anything new.
diff --git a/src/or/entrynodes.h b/src/or/entrynodes.h
index 52b8dc0..b02cd48 100644
--- a/src/or/entrynodes.h
+++ b/src/or/entrynodes.h
@@ -118,6 +118,7 @@ struct transport_t;
 int find_transport_by_bridge_addrport(const tor_addr_t *addr, uint16_t port,
                                       const struct transport_t **transport);
 
+int transport_is_needed(const char *transport_name);
 int validate_pluggable_transports_config(void);
 
 double pathbias_get_close_success_count(entry_guard_t *guard);
-- 
1.8.1.2

From 54f75531a9613ee7b964be93b0051bc75322e7e3 Mon Sep 17 00:00:00 2001
From: David Fifield <david@bamsoftware.com>
Date: Sat, 26 Oct 2013 14:34:48 -0700
Subject: [PATCH 2/4] Simplify transport_is_needed.

By Roger at
https://trac.torproject.org/projects/tor/ticket/5018#comment:11.
---
 src/or/entrynodes.c | 14 ++++----------
 1 file changed, 4 insertions(+), 10 deletions(-)

diff --git a/src/or/entrynodes.c b/src/or/entrynodes.c
index 4062cee..98a01c5 100644
--- a/src/or/entrynodes.c
+++ b/src/or/entrynodes.c
@@ -1778,22 +1778,16 @@ bridge_resolve_conflicts(const tor_addr_t *addr, uint16_t port,
 int
 transport_is_needed(const char *transport_name)
 {
-  int retval;
-  smartlist_t *needed_transports = NULL;
-
   if (!bridge_list)
     return 0;
 
-  needed_transports = smartlist_new();
-
   SMARTLIST_FOREACH_BEGIN(bridge_list, const bridge_info_t *, bridge) {
-    if (bridge->transport_name)
-      smartlist_add(needed_transports, bridge->transport_name);
+    if (bridge->transport_name &&
+        !strcmp(bridge->transport_name, transport_name))
+      return 1;
   } SMARTLIST_FOREACH_END(bridge);
 
-  retval = smartlist_string_isin(needed_transports, transport_name);
-  smartlist_free(needed_transports);
-  return retval;
+  return 0;
 }
 
 /** Remember a new bridge at <b>addr</b>:<b>port</b>. If <b>digest</b>
-- 
1.8.1.2

From 936ff64974b00a898fa0e77e3fd6f9b2df57f448 Mon Sep 17 00:00:00 2001
From: David Fifield <david@bamsoftware.com>
Date: Sat, 26 Oct 2013 14:37:50 -0700
Subject: [PATCH 3/4] Document that unneeded transports are ignored.

Suggested by Roger in
https://trac.torproject.org/projects/tor/ticket/5018#comment:11.
---
 src/or/config.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/or/config.c b/src/or/config.c
index 47510c5..435d981 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -4220,7 +4220,8 @@ parse_bridge_line(const char *line, int validate_only)
  * <b>line</b>. Return 0 if the line is well-formed, and -1 if it
  * isn't.
  *
- * If <b>validate_only</b> is 0, and the line is well-formed:
+ * If <b>validate_only</b> is 0, the line is well-formed, and the
+ * transport is needed by some bridge:
  * - If it's an external proxy line, add the transport described in the line to
  * our internal transport list.
  * - If it's a managed proxy line, launch the managed proxy. */
-- 
1.8.1.2

From a4cf8514af1d2dbfd15857af83076577b7dcc4ee Mon Sep 17 00:00:00 2001
From: George Kadianakis <desnacked@riseup.net>
Date: Mon, 10 Mar 2014 22:05:31 +0000
Subject: [PATCH 4/4]  Tone down the log message for when we don't need a PT
 proxy.

Conflicts:
	changes/bug5018
---
 src/or/config.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/or/config.c b/src/or/config.c
index 435d981..914c3de 100644
--- a/src/or/config.c
+++ b/src/or/config.c
@@ -4295,8 +4295,8 @@ parse_client_transport_line(const char *line, int validate_only)
 
   if (is_managed) { /* managed */
     if (!validate_only && is_useless_proxy) {
-      log_warn(LD_GENERAL, "Pluggable transport proxy (%s) does not provide "
-               "any needed transports and will not be launched.", line);
+      log_notice(LD_GENERAL, "Pluggable transport proxy (%s) does not provide "
+                 "any needed transports and will not be launched.", line);
     }
 
     /* If we are not just validating, use the rest of the line as the
-- 
1.8.1.2

