diff options
author | Nick Mathewson <nickm@torproject.org> | 2012-11-27 22:18:16 -0500 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2012-11-27 22:18:16 -0500 |
commit | 190c1d4981e5751aabd3d894095851c830f1d570 (patch) | |
tree | a832d932339382cb7f43fb33a255d7507e037c2e | |
parent | 267c0e5aa14deeb2ca0d7997b4ef5a5c2bbf5fd4 (diff) | |
parent | 6f21d2e49657ada264cace9da7cf6945b4fc073d (diff) | |
download | tor-190c1d4981e5751aabd3d894095851c830f1d570.tar.gz tor-190c1d4981e5751aabd3d894095851c830f1d570.zip |
Merge branch 'bug7013_take2_squashed'
-rw-r--r-- | changes/bug7013 | 4 | ||||
-rw-r--r-- | doc/tor.1.txt | 5 | ||||
-rw-r--r-- | src/common/address.c | 41 | ||||
-rw-r--r-- | src/common/address.h | 3 | ||||
-rw-r--r-- | src/or/config.c | 94 | ||||
-rw-r--r-- | src/or/config.h | 2 | ||||
-rw-r--r-- | src/or/or.h | 3 | ||||
-rw-r--r-- | src/or/statefile.c | 11 | ||||
-rw-r--r-- | src/test/test_addr.c | 53 |
9 files changed, 214 insertions, 2 deletions
diff --git a/changes/bug7013 b/changes/bug7013 new file mode 100644 index 0000000000..ba78520166 --- /dev/null +++ b/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. diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 1e1ff1e839..1a7f8d597b 100644 --- a/doc/tor.1.txt +++ b/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 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 }; |