Browse Source

Merge branch 'bug7013_take2_squashed'

Nick Mathewson 11 years ago
parent
commit
190c1d4981
9 changed files with 214 additions and 2 deletions
  1. 4 0
      changes/bug7013
  2. 5 0
      doc/tor.1.txt
  3. 40 1
      src/common/address.c
  4. 3 0
      src/common/address.h
  5. 94 0
      src/or/config.c
  6. 2 0
      src/or/config.h
  7. 3 0
      src/or/or.h
  8. 10 1
      src/or/statefile.c
  9. 53 0
      src/test/test_addr.c

+ 4 - 0
changes/bug7013

@@ -0,0 +1,4 @@
+  o Minor features:
+    - Add a new torrc option 'ServerTransportListenAddr' which allows
+      users to select the address where their pluggable transports
+      will listen for connections.

+ 5 - 0
doc/tor.1.txt

@@ -181,6 +181,11 @@ GENERAL OPTIONS
     using __options__ as its command-line options, and expects to receive
     proxied client traffic from it.
 
+**ServerTransportListenAddr** __transport__ __IP__:__PORT__::
+    When this option is set, Tor will suggest __IP__:__PORT__ as the
+    listening address of any pluggable transport proxy that tries to
+    launch __transport__.
+
 **ConnLimit** __NUM__::
     The minimum number of file descriptors that must be available to the Tor
     process before it will start. Tor will ask the OS for as many file

+ 40 - 1
src/common/address.c

@@ -1430,7 +1430,46 @@ is_internal_IP(uint32_t ip, int for_listening)
   return tor_addr_is_internal(&myaddr, for_listening);
 }
 
-/** Given an address of the form "host:port", try to divide it into its host
+/** Given an address of the form "ip:port", try to divide it into its
+ * ip and port portions, setting *<b>address_out</b> to a newly
+ * allocated string holding the address portion and *<b>port_out</b>
+ * to the port.
+ *
+ * Don't do DNS lookups and don't allow domain names in the <ip> field.
+ * Don't accept <b>addrport</b> of the form "<ip>" or "<ip>:0".
+ *
+ * Return 0 on success, -1 on failure. */
+int
+tor_addr_port_parse(int severity, const char *addrport,
+                    tor_addr_t *address_out, uint16_t *port_out)
+{
+  int retval = -1;
+  int r;
+  char *addr_tmp = NULL;
+
+  tor_assert(addrport);
+  tor_assert(address_out);
+  tor_assert(port_out);
+
+  r = tor_addr_port_split(severity, addrport, &addr_tmp, port_out);
+  if (r < 0)
+    goto done;
+
+  if (!*port_out)
+    goto done;
+
+  /* make sure that address_out is an IP address */
+  if (tor_addr_parse(address_out, addr_tmp) < 0)
+    goto done;
+
+  retval = 0;
+
+ done:
+  tor_free(addr_tmp);
+  return retval;
+}
+
+/** Given an address of the form "host[:port]", try to divide it into its host
  * ane port portions, setting *<b>address_out</b> to a newly allocated string
  * holding the address portion and *<b>port_out</b> to the port (or 0 if no
  * port is given).  Return 0 on success, -1 on failure. */

+ 3 - 0
src/common/address.h

@@ -208,6 +208,9 @@ int tor_addr_is_loopback(const tor_addr_t *addr);
 int tor_addr_port_split(int severity, const char *addrport,
                         char **address_out, uint16_t *port_out);
 
+int tor_addr_port_parse(int severity, const char *addrport,
+                        tor_addr_t *address_out, uint16_t *port_out);
+
 int tor_addr_hostname_is_local(const char *name);
 
 /* IPv4 helpers */

+ 94 - 0
src/or/config.c

@@ -278,6 +278,7 @@ static config_var_t option_vars_[] = {
   V(HTTPSProxyAuthenticator,     STRING,   NULL),
   V(IPv6Exit,                    BOOL,     "0"),
   VAR("ServerTransportPlugin",   LINELIST, ServerTransportPlugin,  NULL),
+  V(ServerTransportListenAddr,   LINELIST, NULL),
   V(Socks4Proxy,                 STRING,   NULL),
   V(Socks5Proxy,                 STRING,   NULL),
   V(Socks5ProxyUsername,         STRING,   NULL),
@@ -467,6 +468,9 @@ static int parse_bridge_line(const char *line, int validate_only);
 static int parse_client_transport_line(const char *line, int validate_only);
 
 static int parse_server_transport_line(const char *line, int validate_only);
+static char *get_bindaddr_from_transport_listen_line(const char *line,
+                                                     const char *transport);
+
 static int parse_dir_server_line(const char *line,
                                  dirinfo_type_t required_type,
                                  int validate_only);
@@ -2869,6 +2873,22 @@ options_validate(or_options_t *old_options, or_options_t *options,
                escaped(options->ServerTransportPlugin->value));
   }
 
+  for (cl = options->ServerTransportListenAddr; cl; cl = cl->next) {
+    /** If get_bindaddr_from_transport_listen_line() fails with
+        'transport' being NULL, it means that something went wrong
+        while parsing the ServerTransportListenAddr line. */
+    char *bindaddr = get_bindaddr_from_transport_listen_line(cl->value, NULL);
+    if (!bindaddr)
+      REJECT("ServerTransportListenAddr did not parse. See logs for details.");
+    tor_free(bindaddr);
+  }
+
+  if (options->ServerTransportListenAddr && !options->ServerTransportPlugin) {
+    log_notice(LD_GENERAL, "You need at least a single managed-proxy to "
+               "specify a transport listen address. The "
+               "ServerTransportListenAddr line will be ignored.");
+  }
+
   if (options->ConstrainedSockets) {
     /* If the user wants to constrain socket buffer use, make sure the desired
      * limit is between MIN|MAX_TCPSOCK_BUFFER in k increments. */
@@ -4108,6 +4128,80 @@ parse_client_transport_line(const char *line, int validate_only)
   return r;
 }
 
+/** Given a ServerTransportListenAddr <b>line</b>, return its
+ *  <address:port> string. Return NULL if the line was not
+ *  well-formed.
+ *
+ *  If <b>transport</b> is set, return NULL if the line is not
+ *  referring to <b>transport</b>.
+ *
+ *  The returned string is allocated on the heap and it's the
+ *  responsibility of the caller to free it. */
+static char *
+get_bindaddr_from_transport_listen_line(const char *line,const char *transport)
+{
+  smartlist_t *items = NULL;
+  const char *parsed_transport = NULL;
+  char *addrport = NULL;
+  tor_addr_t addr;
+  uint16_t port = 0;
+
+  items = smartlist_new();
+  smartlist_split_string(items, line, NULL,
+                         SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, -1);
+
+  if (smartlist_len(items) < 2) {
+    log_warn(LD_CONFIG,"Too few arguments on ServerTransportListenAddr line.");
+    goto err;
+  }
+
+  parsed_transport = smartlist_get(items, 0);
+  addrport = tor_strdup(smartlist_get(items, 1));
+
+  /* If 'transport' is given, check if it matches the one on the line */
+  if (transport && strcmp(transport, parsed_transport))
+    goto err;
+
+  /* Validate addrport */
+  if (tor_addr_port_parse(LOG_WARN, addrport, &addr, &port)<0) {
+    log_warn(LD_CONFIG, "Error parsing ServerTransportListenAddr "
+             "address '%s'", addrport);
+    goto err;
+  }
+
+  goto done;
+
+ err:
+  tor_free(addrport);
+  addrport = NULL;
+
+ done:
+  SMARTLIST_FOREACH(items, char*, s, tor_free(s));
+  smartlist_free(items);
+
+  return addrport;
+}
+
+/** Given the name of a pluggable transport in <b>transport</b>, check
+ *  the configuration file to see if the user has explicitly asked for
+ *  it to listen on a specific port. Return a <address:port> string if
+ *  so, otherwise NULL. */
+char *
+get_transport_bindaddr_from_config(const char *transport)
+{
+  config_line_t *cl;
+  const or_options_t *options = get_options();
+
+  for (cl = options->ServerTransportListenAddr; cl; cl = cl->next) {
+    char *bindaddr =
+      get_bindaddr_from_transport_listen_line(cl->value, transport);
+    if (bindaddr)
+      return bindaddr;
+  }
+
+  return NULL;
+}
+
 /** Read the contents of a ServerTransportPlugin line from
  * <b>line</b>. Return 0 if the line is well-formed, and -1 if it
  * isn't.

+ 2 - 0
src/or/config.h

@@ -82,6 +82,8 @@ const char *tor_get_digests(void);
 uint32_t get_effective_bwrate(const or_options_t *options);
 uint32_t get_effective_bwburst(const or_options_t *options);
 
+char *get_transport_bindaddr_from_config(const char *transport);
+
 #ifdef CONFIG_PRIVATE
 /* Used only by config.c and test.c */
 or_options_t *options_new(void);

+ 3 - 0
src/or/or.h

@@ -3260,6 +3260,9 @@ typedef struct {
   config_line_t *ServerTransportPlugin; /**< List of client
                                            transport plugins. */
 
+  /** List of TCP/IP addresses that transports should listen at. */
+  config_line_t *ServerTransportListenAddr;
+
   int BridgeRelay; /**< Boolean: are we acting as a bridge relay? We make
                     * this explicit so we can change how we behave in the
                     * future. */

+ 10 - 1
src/or/statefile.c

@@ -517,8 +517,17 @@ get_stored_bindaddr_for_server_transport(const char *transport)
 {
   char *default_addrport = NULL;
   const char *stored_bindaddr = NULL;
+  config_line_t *line = NULL;
+
+  {
+    /* See if the user explicitly asked for a specific listening
+       address for this transport. */
+    char *conf_bindaddr = get_transport_bindaddr_from_config(transport);
+    if (conf_bindaddr)
+      return conf_bindaddr;
+  }
 
-  config_line_t *line = get_transport_in_state_by_name(transport);
+  line = get_transport_in_state_by_name(transport);
   if (!line) /* Found no references in state for this transport. */
     goto no_bindaddr_found;
 

+ 53 - 0
src/test/test_addr.c

@@ -721,12 +721,65 @@ test_addr_ip6_helpers(void)
   ;
 }
 
+/** Test tor_addr_port_parse(). */
+static void
+test_addr_parse(void)
+{
+  int r;
+  tor_addr_t addr;
+  char buf[TOR_ADDR_BUF_LEN];
+  uint16_t port = 0;
+
+  /* Correct call. */
+  r= tor_addr_port_parse(LOG_DEBUG,
+                         "192.0.2.1:1234",
+                         &addr, &port);
+  test_assert(r == 0);
+  tor_addr_to_str(buf, &addr, sizeof(buf), 0);
+  test_streq(buf, "192.0.2.1");
+  test_eq(port, 1234);
+
+  /* Domain name. */
+  r= tor_addr_port_parse(LOG_DEBUG,
+                         "torproject.org:1234",
+                         &addr, &port);
+  test_assert(r == -1);
+
+  /* Only IP. */
+  r= tor_addr_port_parse(LOG_DEBUG,
+                         "192.0.2.2",
+                         &addr, &port);
+  test_assert(r == -1);
+
+  /* Bad port. */
+  r= tor_addr_port_parse(LOG_DEBUG,
+                         "192.0.2.2:66666",
+                         &addr, &port);
+  test_assert(r == -1);
+
+  /* Only domain name */
+  r= tor_addr_port_parse(LOG_DEBUG,
+                         "torproject.org",
+                         &addr, &port);
+  test_assert(r == -1);
+
+  /* Bad IP address */
+  r= tor_addr_port_parse(LOG_DEBUG,
+                         "192.0.2:1234",
+                         &addr, &port);
+  test_assert(r == -1);
+
+ done:
+  ;
+}
+
 #define ADDR_LEGACY(name)                                               \
   { #name, legacy_test_helper, 0, &legacy_setup, test_addr_ ## name }
 
 struct testcase_t addr_tests[] = {
   ADDR_LEGACY(basic),
   ADDR_LEGACY(ip6_helpers),
+  ADDR_LEGACY(parse),
   END_OF_TESTCASES
 };