aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2012-11-27 22:18:16 -0500
committerNick Mathewson <nickm@torproject.org>2012-11-27 22:18:16 -0500
commit190c1d4981e5751aabd3d894095851c830f1d570 (patch)
treea832d932339382cb7f43fb33a255d7507e037c2e /src
parent267c0e5aa14deeb2ca0d7997b4ef5a5c2bbf5fd4 (diff)
parent6f21d2e49657ada264cace9da7cf6945b4fc073d (diff)
downloadtor-190c1d4981e5751aabd3d894095851c830f1d570.tar.gz
tor-190c1d4981e5751aabd3d894095851c830f1d570.zip
Merge branch 'bug7013_take2_squashed'
Diffstat (limited to 'src')
-rw-r--r--src/common/address.c41
-rw-r--r--src/common/address.h3
-rw-r--r--src/or/config.c94
-rw-r--r--src/or/config.h2
-rw-r--r--src/or/or.h3
-rw-r--r--src/or/statefile.c11
-rw-r--r--src/test/test_addr.c53
7 files changed, 205 insertions, 2 deletions
diff --git a/src/common/address.c b/src/common/address.c
index e94f147ce7..3b844f7993 100644
--- a/src/common/address.c
+++ b/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. */
diff --git a/src/common/address.h b/src/common/address.h
index 9c0df6c24f..0e2bbdcf88 100644
--- a/src/common/address.h
+++ b/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 */
diff --git a/src/or/config.c b/src/or/config.c
index 206ccc80d5..75f6193352 100644
--- a/src/or/config.c
+++ b/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.
diff --git a/src/or/config.h b/src/or/config.h
index f3b28adb78..336685d075 100644
--- a/src/or/config.h
+++ b/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);
diff --git a/src/or/or.h b/src/or/or.h
index a8645f854e..2ac9f6bdeb 100644
--- a/src/or/or.h
+++ b/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. */
diff --git a/src/or/statefile.c b/src/or/statefile.c
index 55ba0c1602..1429efda12 100644
--- a/src/or/statefile.c
+++ b/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;
diff --git a/src/test/test_addr.c b/src/test/test_addr.c
index 6d0fe5afdf..586ceb6102 100644
--- a/src/test/test_addr.c
+++ b/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
};