mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-24 04:13:28 +01:00
Merge branch 'haxxpop/tcp_proxy_squashed' into tcp_proxy_squshed_and_merged
This commit is contained in:
commit
1b63eea66c
6
changes/ticket31518
Normal file
6
changes/ticket31518
Normal file
@ -0,0 +1,6 @@
|
||||
o Major features (proxy):
|
||||
- In addition to HTTP CONNECT, SOCKS4, and SOCKS5, Tor can make all OR
|
||||
connections through the HAProxy server. A new torrc option was added to
|
||||
specify the address/port of the server: TCPProxy <protocol>
|
||||
<host>:<port>. Currently the only supported protocol in the option is
|
||||
haproxy. Close ticket 31518. Patch done by Suphanat Chunhapanya (haxxpop).
|
@ -918,6 +918,22 @@ forward slash (/) in the configuration file and on the command line.
|
||||
log entries are marked with "Tor-__tag__". Can not be changed while tor is
|
||||
running. (Default: none)
|
||||
|
||||
[[TCPProxy]] **TCPProxy** __protocol__ __host__:__port__::
|
||||
Tor will use the given protocol to make all its OR (SSL) connections through
|
||||
a TCP proxy on host:port, rather than connecting directly to servers. You may
|
||||
want to set **FascistFirewall** to restrict the set of ports you might try to
|
||||
connect to, if your proxy only allows connecting to certain ports. There is no
|
||||
equivalent option for directory connections, because all Tor client versions
|
||||
that support this option download directory documents via OR connections. +
|
||||
+
|
||||
The only protocol supported right now 'haproxy'. This option is only for
|
||||
clients. (Default: none) +
|
||||
+
|
||||
The HAProxy version 1 proxy protocol is described in detail at
|
||||
https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt +
|
||||
+
|
||||
Both source IP address and source port will be set to zero.
|
||||
|
||||
[[TruncateLogFile]] **TruncateLogFile** **0**|**1**::
|
||||
If 1, Tor will overwrite logs at startup and in response to a HUP signal,
|
||||
instead of appending to them. (Default: 0)
|
||||
|
@ -538,6 +538,7 @@ static const config_var_t option_vars_[] = {
|
||||
V(Socks5Proxy, STRING, NULL),
|
||||
V(Socks5ProxyUsername, STRING, NULL),
|
||||
V(Socks5ProxyPassword, STRING, NULL),
|
||||
V(TCPProxy, STRING, NULL),
|
||||
VAR_IMMUTABLE("KeyDirectory", FILENAME, KeyDirectory_option, NULL),
|
||||
V(KeyDirectoryGroupReadable, AUTOBOOL, "auto"),
|
||||
VAR_D("HSLayer2Nodes", ROUTERSET, HSLayer2Nodes, NULL),
|
||||
@ -3940,19 +3941,28 @@ options_validate_cb(const void *old_options_, void *options_, char **msg)
|
||||
}
|
||||
}
|
||||
|
||||
if (options->TCPProxy) {
|
||||
int res = parse_tcp_proxy_line(options->TCPProxy, options, msg);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if more than one exclusive proxy type has been enabled. */
|
||||
if (!!options->Socks4Proxy + !!options->Socks5Proxy +
|
||||
!!options->HTTPSProxy > 1)
|
||||
!!options->HTTPSProxy + !!options->TCPProxy > 1)
|
||||
REJECT("You have configured more than one proxy type. "
|
||||
"(Socks4Proxy|Socks5Proxy|HTTPSProxy)");
|
||||
"(Socks4Proxy|Socks5Proxy|HTTPSProxy|TCPProxy)");
|
||||
|
||||
/* Check if the proxies will give surprising behavior. */
|
||||
if (options->HTTPProxy && !(options->Socks4Proxy ||
|
||||
options->Socks5Proxy ||
|
||||
options->HTTPSProxy)) {
|
||||
log_warn(LD_CONFIG, "HTTPProxy configured, but no SOCKS proxy or "
|
||||
"HTTPS proxy configured. Watch out: this configuration will "
|
||||
"proxy unencrypted directory connections only.");
|
||||
options->HTTPSProxy ||
|
||||
options->TCPProxy)) {
|
||||
log_warn(LD_CONFIG, "HTTPProxy configured, but no SOCKS proxy, "
|
||||
"HTTPS proxy, or any other TCP proxy configured. Watch out: "
|
||||
"this configuration will proxy unencrypted directory "
|
||||
"connections only.");
|
||||
}
|
||||
|
||||
if (options->Socks5ProxyUsername) {
|
||||
@ -5348,6 +5358,68 @@ parse_bridge_line(const char *line)
|
||||
return bridge_line;
|
||||
}
|
||||
|
||||
/** Parse the contents of a TCPProxy line from <b>line</b> and put it
|
||||
* in <b>options</b>. Return 0 if the line is well-formed, and -1 if it
|
||||
* isn't.
|
||||
*
|
||||
* This will mutate only options->TCPProxyProtocol, options->TCPProxyAddr,
|
||||
* and options->TCPProxyPort.
|
||||
*
|
||||
* On error, tor_strdup an error explanation into *<b>msg</b>.
|
||||
*/
|
||||
STATIC int
|
||||
parse_tcp_proxy_line(const char *line, or_options_t *options, char **msg)
|
||||
{
|
||||
int ret = 0;
|
||||
tor_assert(line);
|
||||
tor_assert(options);
|
||||
tor_assert(msg);
|
||||
|
||||
smartlist_t *sl = smartlist_new();
|
||||
/* Split between the protocol and the address/port. */
|
||||
smartlist_split_string(sl, line, " ",
|
||||
SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 2);
|
||||
|
||||
/* The address/port is not specified. */
|
||||
if (smartlist_len(sl) < 2) {
|
||||
*msg = tor_strdup("TCPProxy has no address/port. Please fix.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
char *protocol_string = smartlist_get(sl, 0);
|
||||
char *addrport_string = smartlist_get(sl, 1);
|
||||
|
||||
/* The only currently supported protocol is 'haproxy'. */
|
||||
if (strcasecmp(protocol_string, "haproxy")) {
|
||||
*msg = tor_strdup("TCPProxy protocol is not supported. Currently "
|
||||
"the only supported protocol is 'haproxy'. "
|
||||
"Please fix.");
|
||||
goto err;
|
||||
} else {
|
||||
/* Otherwise, set the correct protocol. */
|
||||
options->TCPProxyProtocol = TCP_PROXY_PROTOCOL_HAPROXY;
|
||||
}
|
||||
|
||||
/* Parse the address/port. */
|
||||
if (tor_addr_port_lookup(addrport_string, &options->TCPProxyAddr,
|
||||
&options->TCPProxyPort) < 0) {
|
||||
*msg = tor_strdup("TCPProxy address/port failed to parse or resolve. "
|
||||
"Please fix.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Success. */
|
||||
ret = 0;
|
||||
goto end;
|
||||
|
||||
err:
|
||||
ret = -1;
|
||||
end:
|
||||
SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
|
||||
smartlist_free(sl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Read the contents of a ClientTransportPlugin or ServerTransportPlugin
|
||||
* line from <b>line</b>, depending on the value of <b>server</b>. Return 0
|
||||
* if the line is well-formed, and -1 if it isn't.
|
||||
@ -5495,9 +5567,10 @@ pt_parse_transport_line(const or_options_t *options,
|
||||
|
||||
/* ClientTransportPlugins connecting through a proxy is managed only. */
|
||||
if (!server && (options->Socks4Proxy || options->Socks5Proxy ||
|
||||
options->HTTPSProxy)) {
|
||||
options->HTTPSProxy || options->TCPProxy)) {
|
||||
log_warn(LD_CONFIG, "You have configured an external proxy with another "
|
||||
"proxy type. (Socks4Proxy|Socks5Proxy|HTTPSProxy)");
|
||||
"proxy type. (Socks4Proxy|Socks5Proxy|HTTPSProxy|"
|
||||
"TCPProxy)");
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
@ -286,6 +286,8 @@ STATIC const struct config_mgr_t *get_options_mgr(void);
|
||||
STATIC void or_options_free_(or_options_t *options);
|
||||
STATIC int options_validate_single_onion(or_options_t *options,
|
||||
char **msg);
|
||||
STATIC int parse_tcp_proxy_line(const char *line, or_options_t *options,
|
||||
char **msg);
|
||||
STATIC int consider_adding_dir_servers(const or_options_t *options,
|
||||
const or_options_t *old_options);
|
||||
STATIC void add_default_trusted_dir_authorities(dirinfo_type_t type);
|
||||
|
@ -27,6 +27,12 @@ typedef enum {OUTBOUND_ADDR_EXIT, OUTBOUND_ADDR_OR,
|
||||
OUTBOUND_ADDR_EXIT_AND_OR,
|
||||
OUTBOUND_ADDR_MAX} outbound_addr_t;
|
||||
|
||||
/** Which protocol to use for TCPProxy. */
|
||||
typedef enum {
|
||||
/** Use the HAProxy proxy protocol. */
|
||||
TCP_PROXY_PROTOCOL_HAPROXY
|
||||
} tcp_proxy_protocol_t;
|
||||
|
||||
/** Configuration options for a Tor process. */
|
||||
struct or_options_t {
|
||||
uint32_t magic_;
|
||||
@ -419,6 +425,11 @@ struct or_options_t {
|
||||
char *Socks5ProxyUsername; /**< Username for SOCKS5 authentication, if any */
|
||||
char *Socks5ProxyPassword; /**< Password for SOCKS5 authentication, if any */
|
||||
|
||||
char *TCPProxy; /**< protocol and hostname:port to use as a proxy, if any. */
|
||||
tcp_proxy_protocol_t TCPProxyProtocol; /**< Derived from TCPProxy. */
|
||||
tor_addr_t TCPProxyAddr; /**< Derived from TCPProxy. */
|
||||
uint16_t TCPProxyPort; /**< Derived from TCPProxy. */
|
||||
|
||||
/** List of configuration lines for replacement directory authorities.
|
||||
* If you just want to replace one class of authority at a time,
|
||||
* use the "Alternate*Authority" options below instead. */
|
||||
|
@ -64,6 +64,7 @@ LIBTOR_APP_A_SOURCES = \
|
||||
src/core/proto/proto_cell.c \
|
||||
src/core/proto/proto_control0.c \
|
||||
src/core/proto/proto_ext_or.c \
|
||||
src/core/proto/proto_haproxy.c \
|
||||
src/core/proto/proto_http.c \
|
||||
src/core/proto/proto_socks.c \
|
||||
src/feature/api/tor_api.c \
|
||||
@ -324,6 +325,7 @@ noinst_HEADERS += \
|
||||
src/core/proto/proto_cell.h \
|
||||
src/core/proto/proto_control0.h \
|
||||
src/core/proto/proto_ext_or.h \
|
||||
src/core/proto/proto_haproxy.h \
|
||||
src/core/proto/proto_http.h \
|
||||
src/core/proto/proto_socks.h \
|
||||
src/feature/api/tor_api_internal.h \
|
||||
|
@ -82,6 +82,7 @@
|
||||
#include "core/or/reasons.h"
|
||||
#include "core/or/relay.h"
|
||||
#include "core/or/crypt_path.h"
|
||||
#include "core/proto/proto_haproxy.h"
|
||||
#include "core/proto/proto_http.h"
|
||||
#include "core/proto/proto_socks.h"
|
||||
#include "feature/client/dnsserv.h"
|
||||
@ -2318,7 +2319,11 @@ conn_get_proxy_type(const connection_t *conn)
|
||||
return PROXY_SOCKS4;
|
||||
else if (options->Socks5Proxy)
|
||||
return PROXY_SOCKS5;
|
||||
else
|
||||
else if (options->TCPProxy) {
|
||||
/* The only supported protocol in TCPProxy is haproxy. */
|
||||
tor_assert(options->TCPProxyProtocol == TCP_PROXY_PROTOCOL_HAPROXY);
|
||||
return PROXY_HAPROXY;
|
||||
} else
|
||||
return PROXY_NONE;
|
||||
}
|
||||
|
||||
@ -2327,10 +2332,202 @@ conn_get_proxy_type(const connection_t *conn)
|
||||
username NUL: */
|
||||
#define SOCKS4_STANDARD_BUFFER_SIZE (1 + 1 + 2 + 4 + 1)
|
||||
|
||||
/** Write a proxy request of <b>type</b> (socks4, socks5, https) to conn
|
||||
* for conn->addr:conn->port, authenticating with the auth details given
|
||||
* in the configuration (if available). SOCKS 5 and HTTP CONNECT proxies
|
||||
* support authentication.
|
||||
/** Write a proxy request of https to conn for conn->addr:conn->port,
|
||||
* authenticating with the auth details given in the configuration
|
||||
* (if available).
|
||||
*
|
||||
* Returns -1 if conn->addr is incompatible with the proxy protocol, and
|
||||
* 0 otherwise.
|
||||
*/
|
||||
static int
|
||||
connection_https_proxy_connect(connection_t *conn)
|
||||
{
|
||||
tor_assert(conn);
|
||||
|
||||
const or_options_t *options = get_options();
|
||||
char buf[1024];
|
||||
char *base64_authenticator = NULL;
|
||||
const char *authenticator = options->HTTPSProxyAuthenticator;
|
||||
|
||||
/* Send HTTP CONNECT and authentication (if available) in
|
||||
* one request */
|
||||
|
||||
if (authenticator) {
|
||||
base64_authenticator = alloc_http_authenticator(authenticator);
|
||||
if (!base64_authenticator)
|
||||
log_warn(LD_OR, "Encoding https authenticator failed");
|
||||
}
|
||||
|
||||
if (base64_authenticator) {
|
||||
const char *addrport = fmt_addrport(&conn->addr, conn->port);
|
||||
tor_snprintf(buf, sizeof(buf), "CONNECT %s HTTP/1.1\r\n"
|
||||
"Host: %s\r\n"
|
||||
"Proxy-Authorization: Basic %s\r\n\r\n",
|
||||
addrport,
|
||||
addrport,
|
||||
base64_authenticator);
|
||||
tor_free(base64_authenticator);
|
||||
} else {
|
||||
tor_snprintf(buf, sizeof(buf), "CONNECT %s HTTP/1.0\r\n\r\n",
|
||||
fmt_addrport(&conn->addr, conn->port));
|
||||
}
|
||||
|
||||
connection_buf_add(buf, strlen(buf), conn);
|
||||
conn->proxy_state = PROXY_HTTPS_WANT_CONNECT_OK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Write a proxy request of socks4 to conn for conn->addr:conn->port.
|
||||
*
|
||||
* Returns -1 if conn->addr is incompatible with the proxy protocol, and
|
||||
* 0 otherwise.
|
||||
*/
|
||||
static int
|
||||
connection_socks4_proxy_connect(connection_t *conn)
|
||||
{
|
||||
tor_assert(conn);
|
||||
|
||||
unsigned char *buf;
|
||||
uint16_t portn;
|
||||
uint32_t ip4addr;
|
||||
size_t buf_size = 0;
|
||||
char *socks_args_string = NULL;
|
||||
|
||||
/* Send a SOCKS4 connect request */
|
||||
|
||||
if (tor_addr_family(&conn->addr) != AF_INET) {
|
||||
log_warn(LD_NET, "SOCKS4 client is incompatible with IPv6");
|
||||
return -1;
|
||||
}
|
||||
|
||||
{ /* If we are here because we are trying to connect to a
|
||||
pluggable transport proxy, check if we have any SOCKS
|
||||
arguments to transmit. If we do, compress all arguments to
|
||||
a single string in 'socks_args_string': */
|
||||
|
||||
if (conn_get_proxy_type(conn) == PROXY_PLUGGABLE) {
|
||||
socks_args_string =
|
||||
pt_get_socks_args_for_proxy_addrport(&conn->addr, conn->port);
|
||||
if (socks_args_string)
|
||||
log_debug(LD_NET, "Sending out '%s' as our SOCKS argument string.",
|
||||
socks_args_string);
|
||||
}
|
||||
}
|
||||
|
||||
{ /* Figure out the buffer size we need for the SOCKS message: */
|
||||
|
||||
buf_size = SOCKS4_STANDARD_BUFFER_SIZE;
|
||||
|
||||
/* If we have a SOCKS argument string, consider its size when
|
||||
calculating the buffer size: */
|
||||
if (socks_args_string)
|
||||
buf_size += strlen(socks_args_string);
|
||||
}
|
||||
|
||||
buf = tor_malloc_zero(buf_size);
|
||||
|
||||
ip4addr = tor_addr_to_ipv4n(&conn->addr);
|
||||
portn = htons(conn->port);
|
||||
|
||||
buf[0] = 4; /* version */
|
||||
buf[1] = SOCKS_COMMAND_CONNECT; /* command */
|
||||
memcpy(buf + 2, &portn, 2); /* port */
|
||||
memcpy(buf + 4, &ip4addr, 4); /* addr */
|
||||
|
||||
/* Next packet field is the userid. If we have pluggable
|
||||
transport SOCKS arguments, we have to embed them
|
||||
there. Otherwise, we use an empty userid. */
|
||||
if (socks_args_string) { /* place the SOCKS args string: */
|
||||
tor_assert(strlen(socks_args_string) > 0);
|
||||
tor_assert(buf_size >=
|
||||
SOCKS4_STANDARD_BUFFER_SIZE + strlen(socks_args_string));
|
||||
strlcpy((char *)buf + 8, socks_args_string, buf_size - 8);
|
||||
tor_free(socks_args_string);
|
||||
} else {
|
||||
buf[8] = 0; /* no userid */
|
||||
}
|
||||
|
||||
connection_buf_add((char *)buf, buf_size, conn);
|
||||
tor_free(buf);
|
||||
|
||||
conn->proxy_state = PROXY_SOCKS4_WANT_CONNECT_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Write a proxy request of socks5 to conn for conn->addr:conn->port,
|
||||
* authenticating with the auth details given in the configuration
|
||||
* (if available).
|
||||
*
|
||||
* Returns -1 if conn->addr is incompatible with the proxy protocol, and
|
||||
* 0 otherwise.
|
||||
*/
|
||||
static int
|
||||
connection_socks5_proxy_connect(connection_t *conn)
|
||||
{
|
||||
tor_assert(conn);
|
||||
|
||||
const or_options_t *options = get_options();
|
||||
unsigned char buf[4]; /* fields: vers, num methods, method list */
|
||||
|
||||
/* Send a SOCKS5 greeting (connect request must wait) */
|
||||
|
||||
buf[0] = 5; /* version */
|
||||
|
||||
/* We have to use SOCKS5 authentication, if we have a
|
||||
Socks5ProxyUsername or if we want to pass arguments to our
|
||||
pluggable transport proxy: */
|
||||
if ((options->Socks5ProxyUsername) ||
|
||||
(conn_get_proxy_type(conn) == PROXY_PLUGGABLE &&
|
||||
(get_socks_args_by_bridge_addrport(&conn->addr, conn->port)))) {
|
||||
/* number of auth methods */
|
||||
buf[1] = 2;
|
||||
buf[2] = 0x00; /* no authentication */
|
||||
buf[3] = 0x02; /* rfc1929 Username/Passwd auth */
|
||||
conn->proxy_state = PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929;
|
||||
} else {
|
||||
buf[1] = 1;
|
||||
buf[2] = 0x00; /* no authentication */
|
||||
conn->proxy_state = PROXY_SOCKS5_WANT_AUTH_METHOD_NONE;
|
||||
}
|
||||
|
||||
connection_buf_add((char *)buf, 2 + buf[1], conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Write a proxy request of haproxy to conn for conn->addr:conn->port.
|
||||
*
|
||||
* Returns -1 if conn->addr is incompatible with the proxy protocol, and
|
||||
* 0 otherwise.
|
||||
*/
|
||||
static int
|
||||
connection_haproxy_proxy_connect(connection_t *conn)
|
||||
{
|
||||
int ret = 0;
|
||||
tor_addr_port_t *addr_port = tor_addr_port_new(&conn->addr, conn->port);
|
||||
char *buf = haproxy_format_proxy_header_line(addr_port);
|
||||
|
||||
if (buf == NULL) {
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
connection_buf_add(buf, strlen(buf), conn);
|
||||
/* In haproxy, we don't have to wait for the response, but we wait for ack.
|
||||
* So we can set the state to be PROXY_HAPROXY_WAIT_FOR_FLUSH. */
|
||||
conn->proxy_state = PROXY_HAPROXY_WAIT_FOR_FLUSH;
|
||||
|
||||
ret = 0;
|
||||
done:
|
||||
tor_free(buf);
|
||||
tor_free(addr_port);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Write a proxy request of <b>type</b> (socks4, socks5, https, haproxy)
|
||||
* to conn for conn->addr:conn->port, authenticating with the auth details
|
||||
* given in the configuration (if available). SOCKS 5 and HTTP CONNECT
|
||||
* proxies support authentication.
|
||||
*
|
||||
* Returns -1 if conn->addr is incompatible with the proxy protocol, and
|
||||
* 0 otherwise.
|
||||
@ -2340,152 +2537,40 @@ conn_get_proxy_type(const connection_t *conn)
|
||||
int
|
||||
connection_proxy_connect(connection_t *conn, int type)
|
||||
{
|
||||
const or_options_t *options;
|
||||
int ret = 0;
|
||||
|
||||
tor_assert(conn);
|
||||
|
||||
options = get_options();
|
||||
|
||||
switch (type) {
|
||||
case PROXY_CONNECT: {
|
||||
char buf[1024];
|
||||
char *base64_authenticator=NULL;
|
||||
const char *authenticator = options->HTTPSProxyAuthenticator;
|
||||
|
||||
/* Send HTTP CONNECT and authentication (if available) in
|
||||
* one request */
|
||||
|
||||
if (authenticator) {
|
||||
base64_authenticator = alloc_http_authenticator(authenticator);
|
||||
if (!base64_authenticator)
|
||||
log_warn(LD_OR, "Encoding https authenticator failed");
|
||||
}
|
||||
|
||||
if (base64_authenticator) {
|
||||
const char *addrport = fmt_addrport(&conn->addr, conn->port);
|
||||
tor_snprintf(buf, sizeof(buf), "CONNECT %s HTTP/1.1\r\n"
|
||||
"Host: %s\r\n"
|
||||
"Proxy-Authorization: Basic %s\r\n\r\n",
|
||||
addrport,
|
||||
addrport,
|
||||
base64_authenticator);
|
||||
tor_free(base64_authenticator);
|
||||
} else {
|
||||
tor_snprintf(buf, sizeof(buf), "CONNECT %s HTTP/1.0\r\n\r\n",
|
||||
fmt_addrport(&conn->addr, conn->port));
|
||||
}
|
||||
|
||||
connection_buf_add(buf, strlen(buf), conn);
|
||||
conn->proxy_state = PROXY_HTTPS_WANT_CONNECT_OK;
|
||||
case PROXY_CONNECT:
|
||||
ret = connection_https_proxy_connect(conn);
|
||||
break;
|
||||
}
|
||||
|
||||
case PROXY_SOCKS4: {
|
||||
unsigned char *buf;
|
||||
uint16_t portn;
|
||||
uint32_t ip4addr;
|
||||
size_t buf_size = 0;
|
||||
char *socks_args_string = NULL;
|
||||
|
||||
/* Send a SOCKS4 connect request */
|
||||
|
||||
if (tor_addr_family(&conn->addr) != AF_INET) {
|
||||
log_warn(LD_NET, "SOCKS4 client is incompatible with IPv6");
|
||||
return -1;
|
||||
}
|
||||
|
||||
{ /* If we are here because we are trying to connect to a
|
||||
pluggable transport proxy, check if we have any SOCKS
|
||||
arguments to transmit. If we do, compress all arguments to
|
||||
a single string in 'socks_args_string': */
|
||||
|
||||
if (conn_get_proxy_type(conn) == PROXY_PLUGGABLE) {
|
||||
socks_args_string =
|
||||
pt_get_socks_args_for_proxy_addrport(&conn->addr, conn->port);
|
||||
if (socks_args_string)
|
||||
log_debug(LD_NET, "Sending out '%s' as our SOCKS argument string.",
|
||||
socks_args_string);
|
||||
}
|
||||
}
|
||||
|
||||
{ /* Figure out the buffer size we need for the SOCKS message: */
|
||||
|
||||
buf_size = SOCKS4_STANDARD_BUFFER_SIZE;
|
||||
|
||||
/* If we have a SOCKS argument string, consider its size when
|
||||
calculating the buffer size: */
|
||||
if (socks_args_string)
|
||||
buf_size += strlen(socks_args_string);
|
||||
}
|
||||
|
||||
buf = tor_malloc_zero(buf_size);
|
||||
|
||||
ip4addr = tor_addr_to_ipv4n(&conn->addr);
|
||||
portn = htons(conn->port);
|
||||
|
||||
buf[0] = 4; /* version */
|
||||
buf[1] = SOCKS_COMMAND_CONNECT; /* command */
|
||||
memcpy(buf + 2, &portn, 2); /* port */
|
||||
memcpy(buf + 4, &ip4addr, 4); /* addr */
|
||||
|
||||
/* Next packet field is the userid. If we have pluggable
|
||||
transport SOCKS arguments, we have to embed them
|
||||
there. Otherwise, we use an empty userid. */
|
||||
if (socks_args_string) { /* place the SOCKS args string: */
|
||||
tor_assert(strlen(socks_args_string) > 0);
|
||||
tor_assert(buf_size >=
|
||||
SOCKS4_STANDARD_BUFFER_SIZE + strlen(socks_args_string));
|
||||
strlcpy((char *)buf + 8, socks_args_string, buf_size - 8);
|
||||
tor_free(socks_args_string);
|
||||
} else {
|
||||
buf[8] = 0; /* no userid */
|
||||
}
|
||||
|
||||
connection_buf_add((char *)buf, buf_size, conn);
|
||||
tor_free(buf);
|
||||
|
||||
conn->proxy_state = PROXY_SOCKS4_WANT_CONNECT_OK;
|
||||
case PROXY_SOCKS4:
|
||||
ret = connection_socks4_proxy_connect(conn);
|
||||
break;
|
||||
}
|
||||
|
||||
case PROXY_SOCKS5: {
|
||||
unsigned char buf[4]; /* fields: vers, num methods, method list */
|
||||
|
||||
/* Send a SOCKS5 greeting (connect request must wait) */
|
||||
|
||||
buf[0] = 5; /* version */
|
||||
|
||||
/* We have to use SOCKS5 authentication, if we have a
|
||||
Socks5ProxyUsername or if we want to pass arguments to our
|
||||
pluggable transport proxy: */
|
||||
if ((options->Socks5ProxyUsername) ||
|
||||
(conn_get_proxy_type(conn) == PROXY_PLUGGABLE &&
|
||||
(get_socks_args_by_bridge_addrport(&conn->addr, conn->port)))) {
|
||||
/* number of auth methods */
|
||||
buf[1] = 2;
|
||||
buf[2] = 0x00; /* no authentication */
|
||||
buf[3] = 0x02; /* rfc1929 Username/Passwd auth */
|
||||
conn->proxy_state = PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929;
|
||||
} else {
|
||||
buf[1] = 1;
|
||||
buf[2] = 0x00; /* no authentication */
|
||||
conn->proxy_state = PROXY_SOCKS5_WANT_AUTH_METHOD_NONE;
|
||||
}
|
||||
|
||||
connection_buf_add((char *)buf, 2 + buf[1], conn);
|
||||
case PROXY_SOCKS5:
|
||||
ret = connection_socks5_proxy_connect(conn);
|
||||
break;
|
||||
|
||||
case PROXY_HAPROXY:
|
||||
ret = connection_haproxy_proxy_connect(conn);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
log_err(LD_BUG, "Invalid proxy protocol, %d", type);
|
||||
tor_fragile_assert();
|
||||
return -1;
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
log_debug(LD_NET, "set state %s",
|
||||
connection_proxy_state_to_string(conn->proxy_state));
|
||||
if (ret == 0) {
|
||||
log_debug(LD_NET, "set state %s",
|
||||
connection_proxy_state_to_string(conn->proxy_state));
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Read conn's inbuf. If the http response from the proxy is all
|
||||
@ -5452,6 +5537,13 @@ get_proxy_addrport(tor_addr_t *addr, uint16_t *port, int *proxy_type,
|
||||
*port = options->Socks5ProxyPort;
|
||||
*proxy_type = PROXY_SOCKS5;
|
||||
return 0;
|
||||
} else if (options->TCPProxy) {
|
||||
tor_addr_copy(addr, &options->TCPProxyAddr);
|
||||
*port = options->TCPProxyPort;
|
||||
/* The only supported protocol in TCPProxy is haproxy. */
|
||||
tor_assert(options->TCPProxyProtocol == TCP_PROXY_PROTOCOL_HAPROXY);
|
||||
*proxy_type = PROXY_HAPROXY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
tor_addr_make_unspec(addr);
|
||||
@ -5489,6 +5581,7 @@ proxy_type_to_string(int proxy_type)
|
||||
case PROXY_CONNECT: return "HTTP";
|
||||
case PROXY_SOCKS4: return "SOCKS4";
|
||||
case PROXY_SOCKS5: return "SOCKS5";
|
||||
case PROXY_HAPROXY: return "HAPROXY";
|
||||
case PROXY_PLUGGABLE: return "pluggable transports SOCKS";
|
||||
case PROXY_NONE: return "NULL";
|
||||
default: tor_assert(0);
|
||||
|
@ -75,8 +75,10 @@ struct buf_t;
|
||||
#define PROXY_SOCKS5_WANT_AUTH_RFC1929_OK 6
|
||||
/* We use a SOCKS5 proxy and we just sent our CONNECT command. */
|
||||
#define PROXY_SOCKS5_WANT_CONNECT_OK 7
|
||||
/* We use an HAPROXY proxy and we just sent the proxy header. */
|
||||
#define PROXY_HAPROXY_WAIT_FOR_FLUSH 8
|
||||
/* We use a proxy and we CONNECTed successfully!. */
|
||||
#define PROXY_CONNECTED 8
|
||||
#define PROXY_CONNECTED 9
|
||||
|
||||
/** State for any listener connection. */
|
||||
#define LISTENER_STATE_READY 0
|
||||
|
@ -95,13 +95,6 @@ static unsigned int
|
||||
connection_or_is_bad_for_new_circs(or_connection_t *or_conn);
|
||||
static void connection_or_mark_bad_for_new_circs(or_connection_t *or_conn);
|
||||
|
||||
/*
|
||||
* Call this when changing connection state, so notifications to the owning
|
||||
* channel can be handled.
|
||||
*/
|
||||
|
||||
static void connection_or_change_state(or_connection_t *conn, uint8_t state);
|
||||
|
||||
static void connection_or_check_canonicity(or_connection_t *conn,
|
||||
int started_here);
|
||||
|
||||
@ -457,8 +450,8 @@ connection_or_state_publish(const or_connection_t *conn, uint8_t state)
|
||||
* be notified.
|
||||
*/
|
||||
|
||||
static void
|
||||
connection_or_change_state(or_connection_t *conn, uint8_t state)
|
||||
MOCK_IMPL(STATIC void,
|
||||
connection_or_change_state,(or_connection_t *conn, uint8_t state))
|
||||
{
|
||||
tor_assert(conn);
|
||||
|
||||
@ -726,6 +719,18 @@ connection_or_finished_flushing(or_connection_t *conn)
|
||||
|
||||
switch (conn->base_.state) {
|
||||
case OR_CONN_STATE_PROXY_HANDSHAKING:
|
||||
/* PROXY_HAPROXY gets connected by receiving an ack. */
|
||||
if (conn->proxy_type == PROXY_HAPROXY) {
|
||||
tor_assert(TO_CONN(conn)->proxy_state == PROXY_HAPROXY_WAIT_FOR_FLUSH);
|
||||
TO_CONN(conn)->proxy_state = PROXY_CONNECTED;
|
||||
|
||||
if (connection_tls_start_handshake(conn, 0) < 0) {
|
||||
/* TLS handshaking error of some kind. */
|
||||
connection_or_close_for_error(conn, 0);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OR_CONN_STATE_OPEN:
|
||||
case OR_CONN_STATE_OR_HANDSHAKING_V2:
|
||||
case OR_CONN_STATE_OR_HANDSHAKING_V3:
|
||||
@ -765,8 +770,9 @@ connection_or_finished_connecting(or_connection_t *or_conn)
|
||||
return -1;
|
||||
}
|
||||
|
||||
connection_start_reading(conn);
|
||||
connection_or_change_state(or_conn, OR_CONN_STATE_PROXY_HANDSHAKING);
|
||||
connection_start_reading(conn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -134,6 +134,13 @@ void connection_or_group_set_badness_(smartlist_t *group, int force);
|
||||
#ifdef CONNECTION_OR_PRIVATE
|
||||
STATIC int should_connect_to_relay(const or_connection_t *or_conn);
|
||||
STATIC void note_or_connect_failed(const or_connection_t *or_conn);
|
||||
|
||||
/*
|
||||
* Call this when changing connection state, so notifications to the owning
|
||||
* channel can be handled.
|
||||
*/
|
||||
MOCK_DECL(STATIC void,connection_or_change_state,
|
||||
(or_connection_t *conn, uint8_t state));
|
||||
#endif
|
||||
|
||||
#ifdef TOR_UNIT_TESTS
|
||||
|
@ -167,12 +167,13 @@ struct curve25519_public_key_t;
|
||||
#define PROXY_CONNECT 1
|
||||
#define PROXY_SOCKS4 2
|
||||
#define PROXY_SOCKS5 3
|
||||
/* !!!! If there is ever a PROXY_* type over 3, we must grow the proxy_type
|
||||
#define PROXY_HAPROXY 4
|
||||
/* !!!! If there is ever a PROXY_* type over 7, we must grow the proxy_type
|
||||
* field in or_connection_t */
|
||||
|
||||
/* Pluggable transport proxy type. Don't use this in or_connection_t,
|
||||
* instead use the actual underlying proxy type (see above). */
|
||||
#define PROXY_PLUGGABLE 4
|
||||
#define PROXY_PLUGGABLE 5
|
||||
|
||||
/** How many circuits do we want simultaneously in-progress to handle
|
||||
* a given stream? */
|
||||
|
@ -63,7 +63,7 @@ struct or_connection_t {
|
||||
|
||||
/** True iff this is an outgoing connection. */
|
||||
unsigned int is_outgoing:1;
|
||||
unsigned int proxy_type:2; /**< One of PROXY_NONE...PROXY_SOCKS5 */
|
||||
unsigned int proxy_type:3; /**< One of PROXY_NONE...PROXY_HAPROXY */
|
||||
unsigned int wide_circ_ids:1;
|
||||
/** True iff this connection has had its bootstrap failure logged with
|
||||
* control_event_bootstrap_problem. */
|
||||
|
@ -4,7 +4,11 @@ orconfig.h
|
||||
|
||||
lib/crypt_ops/*.h
|
||||
lib/buf/*.h
|
||||
lib/malloc/*.h
|
||||
lib/string/*.h
|
||||
|
||||
lib/net/address.h
|
||||
|
||||
trunnel/*.h
|
||||
|
||||
core/proto/*.h
|
||||
core/proto/*.h
|
||||
|
45
src/core/proto/proto_haproxy.c
Normal file
45
src/core/proto/proto_haproxy.c
Normal file
@ -0,0 +1,45 @@
|
||||
/* Copyright (c) 2019, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#define PROTO_HAPROXY_PRIVATE
|
||||
#include "lib/malloc/malloc.h"
|
||||
#include "lib/net/address.h"
|
||||
#include "lib/string/printf.h"
|
||||
#include "core/proto/proto_haproxy.h"
|
||||
|
||||
/** Return a newly allocated PROXY header null-terminated string. Returns NULL
|
||||
* if addr_port->addr is incompatible with the proxy protocol.
|
||||
*/
|
||||
char *
|
||||
haproxy_format_proxy_header_line(const tor_addr_port_t *addr_port)
|
||||
{
|
||||
tor_assert(addr_port);
|
||||
|
||||
sa_family_t family = tor_addr_family(&addr_port->addr);
|
||||
const char *family_string = NULL;
|
||||
const char *src_addr_string = NULL;
|
||||
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
family_string = "TCP4";
|
||||
src_addr_string = "0.0.0.0";
|
||||
break;
|
||||
case AF_INET6:
|
||||
family_string = "TCP6";
|
||||
src_addr_string = "::";
|
||||
break;
|
||||
default:
|
||||
/* Unknown family. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *buf;
|
||||
char addrbuf[TOR_ADDR_BUF_LEN];
|
||||
|
||||
tor_addr_to_str(addrbuf, &addr_port->addr, sizeof(addrbuf), 0);
|
||||
|
||||
tor_asprintf(&buf, "PROXY %s %s %s 0 %d\r\n", family_string, src_addr_string,
|
||||
addrbuf, addr_port->port);
|
||||
|
||||
return buf;
|
||||
}
|
12
src/core/proto/proto_haproxy.h
Normal file
12
src/core/proto/proto_haproxy.h
Normal file
@ -0,0 +1,12 @@
|
||||
/* Copyright (c) 2019, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
#ifndef TOR_PROTO_HAPROXY_H
|
||||
#define TOR_PROTO_HAPROXY_H
|
||||
|
||||
struct tor_addr_port_t;
|
||||
|
||||
char *haproxy_format_proxy_header_line(
|
||||
const struct tor_addr_port_t *addr_port);
|
||||
|
||||
#endif /* !defined(TOR_PROTO_HAPROXY_H) */
|
@ -735,6 +735,9 @@ get_pt_proxy_uri(void)
|
||||
const or_options_t *options = get_options();
|
||||
char *uri = NULL;
|
||||
|
||||
/* XXX: Currently TCPProxy is not supported in TOR_PT_PROXY because
|
||||
* there isn't a standard URI scheme for some proxy protocols, such as
|
||||
* haproxy. */
|
||||
if (options->Socks4Proxy || options->Socks5Proxy || options->HTTPSProxy) {
|
||||
char addr[TOR_ADDR_BUF_LEN+1];
|
||||
|
||||
|
@ -45,6 +45,7 @@ using_proxy(const bt_orconn_t *bto)
|
||||
case PROXY_CONNECT:
|
||||
case PROXY_SOCKS4:
|
||||
case PROXY_SOCKS5:
|
||||
case PROXY_HAPROXY:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -190,6 +190,7 @@ src_test_test_SOURCES += \
|
||||
src/test/test_process_descs.c \
|
||||
src/test/test_prob_distr.c \
|
||||
src/test/test_procmon.c \
|
||||
src/test/test_proto_haproxy.c \
|
||||
src/test/test_proto_http.c \
|
||||
src/test/test_proto_misc.c \
|
||||
src/test/test_protover.c \
|
||||
|
@ -739,6 +739,7 @@ struct testgroup_t testgroups[] = {
|
||||
{ "prob_distr/", prob_distr_tests },
|
||||
{ "procmon/", procmon_tests },
|
||||
{ "process/", process_tests },
|
||||
{ "proto/haproxy/", proto_haproxy_tests },
|
||||
{ "proto/http/", proto_http_tests },
|
||||
{ "proto/misc/", proto_misc_tests },
|
||||
{ "protover/", protover_tests },
|
||||
|
@ -262,6 +262,7 @@ extern struct testcase_t slow_stochastic_prob_distr_tests[];
|
||||
extern struct testcase_t procmon_tests[];
|
||||
extern struct testcase_t process_tests[];
|
||||
extern struct testcase_t process_descs_tests[];
|
||||
extern struct testcase_t proto_haproxy_tests[];
|
||||
extern struct testcase_t proto_http_tests[];
|
||||
extern struct testcase_t proto_misc_tests[];
|
||||
extern struct testcase_t protover_tests[];
|
||||
|
@ -676,6 +676,52 @@ transport_is_needed_mock(const char *transport_name)
|
||||
return transport_is_needed_mock_return;
|
||||
}
|
||||
|
||||
static void
|
||||
test_config_parse_tcp_proxy_line(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
int ret;
|
||||
char *msg = NULL;
|
||||
or_options_t *options = get_options_mutable();
|
||||
|
||||
/* Bad TCPProxy line - too short. */
|
||||
ret = parse_tcp_proxy_line("haproxy", options, &msg);
|
||||
/* Return error. */
|
||||
tt_int_op(ret, OP_EQ, -1);
|
||||
/* Correct error message. */
|
||||
tt_str_op(msg, OP_EQ, "TCPProxy has no address/port. Please fix.");
|
||||
/* Free error message. */
|
||||
tor_free(msg);
|
||||
|
||||
/* Bad TCPProxy line - unsupported protocol. */
|
||||
ret = parse_tcp_proxy_line("unsupported 95.216.163.36:443", options, &msg);
|
||||
tt_int_op(ret, OP_EQ, -1);
|
||||
tt_str_op(msg, OP_EQ, "TCPProxy protocol is not supported. Currently the "
|
||||
"only supported protocol is 'haproxy'. Please fix.");
|
||||
tor_free(msg);
|
||||
|
||||
/* Bad TCPProxy line - unparsable address/port. */
|
||||
ret = parse_tcp_proxy_line("haproxy 95.216.163.36/443", options, &msg);
|
||||
tt_int_op(ret, OP_EQ, -1);
|
||||
tt_str_op(msg, OP_EQ, "TCPProxy address/port failed to parse or resolve. "
|
||||
"Please fix.");
|
||||
tor_free(msg);
|
||||
|
||||
/* Good TCPProxy line - ipv4. */
|
||||
ret = parse_tcp_proxy_line("haproxy 95.216.163.36:443", options, &msg);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
tt_ptr_op(msg, OP_EQ, NULL);
|
||||
tt_int_op(options->TCPProxyProtocol, OP_EQ, TCP_PROXY_PROTOCOL_HAPROXY);
|
||||
/* Correct the address. */
|
||||
tt_assert(tor_addr_eq_ipv4h(&options->TCPProxyAddr, 0x5fd8a324));
|
||||
tt_int_op(options->TCPProxyPort, OP_EQ, 443);
|
||||
tor_free(msg);
|
||||
|
||||
done:
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test parsing for the ClientTransportPlugin and ServerTransportPlugin config
|
||||
* options.
|
||||
@ -6129,6 +6175,7 @@ struct testcase_t config_tests[] = {
|
||||
CONFIG_TEST(parse_bridge_line, 0),
|
||||
CONFIG_TEST(parse_transport_options_line, 0),
|
||||
CONFIG_TEST(parse_transport_plugin_line, TT_FORK),
|
||||
CONFIG_TEST(parse_tcp_proxy_line, TT_FORK),
|
||||
CONFIG_TEST(check_or_create_data_subdir, TT_FORK),
|
||||
CONFIG_TEST(write_to_data_subdir, TT_FORK),
|
||||
CONFIG_TEST(fix_my_family, 0),
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "core/or/or.h"
|
||||
#include "test/test.h"
|
||||
|
||||
#include "app/config/or_options_st.h"
|
||||
#include "core/mainloop/connection.h"
|
||||
#include "core/or/connection_edge.h"
|
||||
#include "feature/hs/hs_common.h"
|
||||
@ -312,6 +313,25 @@ test_conn_download_status_teardown(const struct testcase_t *tc, void *arg)
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void *
|
||||
test_conn_proxy_connect_setup(const struct testcase_t *tc)
|
||||
{
|
||||
return test_conn_get_proxy_or_connection(*(unsigned int *)tc->setup_data);
|
||||
}
|
||||
|
||||
static int
|
||||
test_conn_proxy_connect_teardown(const struct testcase_t *tc, void *arg)
|
||||
{
|
||||
(void)tc;
|
||||
or_connection_t *conn = arg;
|
||||
|
||||
tt_assert(conn);
|
||||
assert_connection_ok(&conn->base_, time(NULL));
|
||||
|
||||
done:
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Like connection_ap_make_link(), but does much less */
|
||||
static connection_t *
|
||||
test_conn_get_linked_connection(connection_t *l_conn, uint8_t state)
|
||||
@ -360,6 +380,10 @@ static struct testcase_setup_t test_conn_download_status_st = {
|
||||
test_conn_download_status_setup, test_conn_download_status_teardown
|
||||
};
|
||||
|
||||
static struct testcase_setup_t test_conn_proxy_connect_st = {
|
||||
test_conn_proxy_connect_setup, test_conn_proxy_connect_teardown
|
||||
};
|
||||
|
||||
static void
|
||||
test_conn_get_basic(void *arg)
|
||||
{
|
||||
@ -788,6 +812,64 @@ test_conn_download_status(void *arg)
|
||||
/* the teardown function removes all the connections in the global list*/;
|
||||
}
|
||||
|
||||
static void
|
||||
test_conn_https_proxy_connect(void *arg)
|
||||
{
|
||||
size_t sz;
|
||||
char *buf = NULL;
|
||||
or_connection_t *conn = arg;
|
||||
|
||||
MOCK(connection_or_change_state, mock_connection_or_change_state);
|
||||
|
||||
tt_int_op(conn->base_.proxy_state, OP_EQ, PROXY_HTTPS_WANT_CONNECT_OK);
|
||||
|
||||
buf = buf_get_contents(conn->base_.outbuf, &sz);
|
||||
tt_str_op(buf, OP_EQ, "CONNECT 127.0.0.1:12345 HTTP/1.0\r\n\r\n");
|
||||
|
||||
done:
|
||||
UNMOCK(connection_or_change_state);
|
||||
tor_free(buf);
|
||||
}
|
||||
|
||||
static int handshake_start_called = 0;
|
||||
|
||||
static int
|
||||
handshake_start(or_connection_t *conn, int receiving)
|
||||
{
|
||||
(void)receiving;
|
||||
|
||||
tor_assert(conn);
|
||||
|
||||
handshake_start_called = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
test_conn_haproxy_proxy_connect(void *arg)
|
||||
{
|
||||
size_t sz;
|
||||
char *buf = NULL;
|
||||
or_connection_t *conn = arg;
|
||||
|
||||
MOCK(connection_or_change_state, mock_connection_or_change_state);
|
||||
MOCK(connection_tls_start_handshake, handshake_start);
|
||||
|
||||
tt_int_op(conn->base_.proxy_state, OP_EQ, PROXY_HAPROXY_WAIT_FOR_FLUSH);
|
||||
|
||||
buf = buf_get_contents(conn->base_.outbuf, &sz);
|
||||
tt_str_op(buf, OP_EQ, "PROXY TCP4 0.0.0.0 127.0.0.1 0 12345\r\n");
|
||||
|
||||
connection_or_finished_flushing(conn);
|
||||
|
||||
tt_int_op(conn->base_.proxy_state, OP_EQ, PROXY_CONNECTED);
|
||||
tt_int_op(handshake_start_called, OP_EQ, 1);
|
||||
|
||||
done:
|
||||
UNMOCK(connection_or_change_state);
|
||||
UNMOCK(connection_tls_start_handshake);
|
||||
tor_free(buf);
|
||||
}
|
||||
|
||||
static node_t test_node;
|
||||
|
||||
static node_t *
|
||||
@ -890,14 +972,24 @@ test_failed_orconn_tracker(void *arg)
|
||||
{ #name "_" #arg, test_conn_##name, fork, &setup, (void *)arg }
|
||||
#endif /* !defined(COCCI) */
|
||||
|
||||
static const unsigned int PROXY_CONNECT_ARG = PROXY_CONNECT;
|
||||
static const unsigned int PROXY_HAPROXY_ARG = PROXY_HAPROXY;
|
||||
|
||||
struct testcase_t connection_tests[] = {
|
||||
CONNECTION_TESTCASE(get_basic, TT_FORK, test_conn_get_basic_st),
|
||||
CONNECTION_TESTCASE(get_rend, TT_FORK, test_conn_get_rend_st),
|
||||
CONNECTION_TESTCASE(get_rsrc, TT_FORK, test_conn_get_rsrc_st),
|
||||
CONNECTION_TESTCASE_ARG(download_status, TT_FORK,
|
||||
|
||||
CONNECTION_TESTCASE_ARG(download_status, TT_FORK,
|
||||
test_conn_download_status_st, FLAV_MICRODESC),
|
||||
CONNECTION_TESTCASE_ARG(download_status, TT_FORK,
|
||||
CONNECTION_TESTCASE_ARG(download_status, TT_FORK,
|
||||
test_conn_download_status_st, FLAV_NS),
|
||||
|
||||
CONNECTION_TESTCASE_ARG(https_proxy_connect, TT_FORK,
|
||||
test_conn_proxy_connect_st, &PROXY_CONNECT_ARG),
|
||||
CONNECTION_TESTCASE_ARG(haproxy_proxy_connect, TT_FORK,
|
||||
test_conn_proxy_connect_st, &PROXY_HAPROXY_ARG),
|
||||
|
||||
//CONNECTION_TESTCASE(func_suffix, TT_FORK, setup_func_pair),
|
||||
{ "failed_orconn_tracker", test_failed_orconn_tracker, TT_FORK, NULL, NULL },
|
||||
END_OF_TESTCASES
|
||||
|
@ -7,6 +7,7 @@
|
||||
/** Some constants used by test_connection and helpers */
|
||||
#define TEST_CONN_FAMILY (AF_INET)
|
||||
#define TEST_CONN_ADDRESS "127.0.0.1"
|
||||
#define TEST_CONN_ADDRESS_2 "127.0.0.2"
|
||||
#define TEST_CONN_PORT (12345)
|
||||
#define TEST_CONN_ADDRESS_PORT "127.0.0.1:12345"
|
||||
#define TEST_CONN_FD_INIT 50
|
||||
|
@ -9,6 +9,7 @@
|
||||
#define ROUTERLIST_PRIVATE
|
||||
#define CONFIG_PRIVATE
|
||||
#define CONNECTION_PRIVATE
|
||||
#define CONNECTION_OR_PRIVATE
|
||||
#define MAINLOOP_PRIVATE
|
||||
|
||||
#include "orconfig.h"
|
||||
@ -19,6 +20,7 @@
|
||||
#include "lib/confmgt/confmgt.h"
|
||||
#include "app/main/subsysmgr.h"
|
||||
#include "core/mainloop/connection.h"
|
||||
#include "core/or/connection_or.h"
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
#include "core/mainloop/mainloop.h"
|
||||
#include "feature/nodelist/nodelist.h"
|
||||
@ -33,6 +35,7 @@
|
||||
|
||||
#include "core/or/cell_st.h"
|
||||
#include "core/or/connection_st.h"
|
||||
#include "core/or/or_connection_st.h"
|
||||
#include "feature/nodelist/node_st.h"
|
||||
#include "core/or/origin_circuit_st.h"
|
||||
#include "feature/nodelist/routerlist_st.h"
|
||||
@ -194,6 +197,14 @@ fake_close_socket(tor_socket_t sock)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Helper for test_conn_get_proxy_or_connection() */
|
||||
void
|
||||
mock_connection_or_change_state(or_connection_t *conn, uint8_t state)
|
||||
{
|
||||
tor_assert(conn);
|
||||
conn->base_.state = state;
|
||||
}
|
||||
|
||||
static int mock_connection_connect_sockaddr_called = 0;
|
||||
static int fake_socket_number = TEST_CONN_FD_INIT;
|
||||
|
||||
@ -228,6 +239,76 @@ mock_connection_connect_sockaddr(connection_t *conn,
|
||||
return 1;
|
||||
}
|
||||
|
||||
or_connection_t *
|
||||
test_conn_get_proxy_or_connection(unsigned int proxy_type)
|
||||
{
|
||||
or_connection_t *conn = NULL;
|
||||
tor_addr_t dst_addr;
|
||||
tor_addr_t proxy_addr;
|
||||
int socket_err = 0;
|
||||
int in_progress = 0;
|
||||
|
||||
MOCK(connection_connect_sockaddr,
|
||||
mock_connection_connect_sockaddr);
|
||||
MOCK(connection_write_to_buf_impl_,
|
||||
connection_write_to_buf_mock);
|
||||
MOCK(connection_or_change_state,
|
||||
mock_connection_or_change_state);
|
||||
MOCK(tor_close_socket, fake_close_socket);
|
||||
|
||||
tor_init_connection_lists();
|
||||
|
||||
conn = or_connection_new(CONN_TYPE_OR, TEST_CONN_FAMILY);
|
||||
tt_assert(conn);
|
||||
|
||||
/* Set up a destination address. */
|
||||
test_conn_lookup_addr_helper(TEST_CONN_ADDRESS, TEST_CONN_FAMILY,
|
||||
&dst_addr);
|
||||
tt_assert(!tor_addr_is_null(&dst_addr));
|
||||
|
||||
conn->proxy_type = proxy_type;
|
||||
conn->base_.proxy_state = PROXY_INFANT;
|
||||
|
||||
tor_addr_copy_tight(&conn->base_.addr, &dst_addr);
|
||||
conn->base_.address = tor_addr_to_str_dup(&dst_addr);
|
||||
conn->base_.port = TEST_CONN_PORT;
|
||||
|
||||
/* Set up a proxy address. */
|
||||
test_conn_lookup_addr_helper(TEST_CONN_ADDRESS_2, TEST_CONN_FAMILY,
|
||||
&proxy_addr);
|
||||
tt_assert(!tor_addr_is_null(&proxy_addr));
|
||||
|
||||
conn->base_.state = OR_CONN_STATE_CONNECTING;
|
||||
|
||||
mock_connection_connect_sockaddr_called = 0;
|
||||
in_progress = connection_connect(TO_CONN(conn), TEST_CONN_ADDRESS_PORT,
|
||||
&proxy_addr, TEST_CONN_PORT, &socket_err);
|
||||
tt_int_op(mock_connection_connect_sockaddr_called, OP_EQ, 1);
|
||||
tt_assert(!socket_err);
|
||||
tt_assert(in_progress == 0 || in_progress == 1);
|
||||
|
||||
assert_connection_ok(TO_CONN(conn), time(NULL));
|
||||
|
||||
in_progress = connection_or_finished_connecting(conn);
|
||||
tt_int_op(in_progress, OP_EQ, 0);
|
||||
|
||||
assert_connection_ok(TO_CONN(conn), time(NULL));
|
||||
|
||||
UNMOCK(connection_connect_sockaddr);
|
||||
UNMOCK(connection_write_to_buf_impl_);
|
||||
UNMOCK(connection_or_change_state);
|
||||
UNMOCK(tor_close_socket);
|
||||
return conn;
|
||||
|
||||
/* On failure */
|
||||
done:
|
||||
UNMOCK(connection_connect_sockaddr);
|
||||
UNMOCK(connection_write_to_buf_impl_);
|
||||
UNMOCK(connection_or_change_state);
|
||||
UNMOCK(tor_close_socket);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Create and return a new connection/stream */
|
||||
connection_t *
|
||||
test_conn_get_connection(uint8_t state, uint8_t type, uint8_t purpose)
|
||||
|
@ -26,6 +26,9 @@ char *buf_get_contents(buf_t *buf, size_t *sz_out);
|
||||
int mock_tor_addr_lookup__fail_on_bad_addrs(const char *name,
|
||||
uint16_t family, tor_addr_t *out);
|
||||
|
||||
void mock_connection_or_change_state(or_connection_t *conn, uint8_t state);
|
||||
|
||||
or_connection_t *test_conn_get_proxy_or_connection(unsigned int proxy_type);
|
||||
connection_t *test_conn_get_connection(uint8_t state,
|
||||
uint8_t type, uint8_t purpose);
|
||||
or_options_t *helper_parse_options(const char *conf);
|
||||
|
@ -2807,7 +2807,7 @@ test_options_validate__proxy(void *ignored)
|
||||
ret = options_validate(NULL, tdata->opt, &msg);
|
||||
tt_int_op(ret, OP_EQ, -1);
|
||||
tt_str_op(msg, OP_EQ, "You have configured more than one proxy type. "
|
||||
"(Socks4Proxy|Socks5Proxy|HTTPSProxy)");
|
||||
"(Socks4Proxy|Socks5Proxy|HTTPSProxy|TCPProxy)");
|
||||
tor_free(msg);
|
||||
|
||||
free_options_test_data(tdata);
|
||||
@ -2815,9 +2815,10 @@ test_options_validate__proxy(void *ignored)
|
||||
mock_clean_saved_logs();
|
||||
ret = options_validate(NULL, tdata->opt, &msg);
|
||||
tt_int_op(ret, OP_EQ, 0);
|
||||
expect_log_msg("HTTPProxy configured, but no SOCKS "
|
||||
"proxy or HTTPS proxy configured. Watch out: this configuration "
|
||||
"will proxy unencrypted directory connections only.\n");
|
||||
expect_log_msg("HTTPProxy configured, but no SOCKS proxy, "
|
||||
"HTTPS proxy, or any other TCP proxy configured. Watch out: "
|
||||
"this configuration will proxy unencrypted directory "
|
||||
"connections only.\n");
|
||||
tor_free(msg);
|
||||
|
||||
free_options_test_data(tdata);
|
||||
|
66
src/test/test_proto_haproxy.c
Normal file
66
src/test/test_proto_haproxy.c
Normal file
@ -0,0 +1,66 @@
|
||||
/* Copyright (c) 2019, The Tor Project, Inc. */
|
||||
/* See LICENSE for licensing information */
|
||||
|
||||
/**
|
||||
* \file test_proto_haproxy.c
|
||||
* \brief Tests for our HAProxy protocol parser code
|
||||
*/
|
||||
|
||||
#define PROTO_HAPROXY_PRIVATE
|
||||
|
||||
#include "test/test.h"
|
||||
#include "core/proto/proto_haproxy.h"
|
||||
#include "test/log_test_helpers.h"
|
||||
|
||||
static void
|
||||
test_format_proxy_header_line(void *arg)
|
||||
{
|
||||
tor_addr_t addr;
|
||||
tor_addr_port_t *addr_port = NULL;
|
||||
char *output = NULL;
|
||||
|
||||
(void) arg;
|
||||
|
||||
/* IPv4 address. */
|
||||
tor_addr_parse(&addr, "192.168.1.2");
|
||||
addr_port = tor_addr_port_new(&addr, 8000);
|
||||
output = haproxy_format_proxy_header_line(addr_port);
|
||||
|
||||
tt_str_op(output, OP_EQ, "PROXY TCP4 0.0.0.0 192.168.1.2 0 8000\r\n");
|
||||
|
||||
tor_free(addr_port);
|
||||
tor_free(output);
|
||||
|
||||
/* IPv6 address. */
|
||||
tor_addr_parse(&addr, "123:45:6789::5005:11");
|
||||
addr_port = tor_addr_port_new(&addr, 8000);
|
||||
output = haproxy_format_proxy_header_line(addr_port);
|
||||
|
||||
tt_str_op(output, OP_EQ, "PROXY TCP6 :: 123:45:6789::5005:11 0 8000\r\n");
|
||||
|
||||
tor_free(addr_port);
|
||||
tor_free(output);
|
||||
|
||||
/* UNIX socket address. */
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.family = AF_UNIX;
|
||||
addr_port = tor_addr_port_new(&addr, 8000);
|
||||
output = haproxy_format_proxy_header_line(addr_port);
|
||||
|
||||
/* If it's not an IPv4 or IPv6 address, haproxy_format_proxy_header_line
|
||||
* must return NULL. */
|
||||
tt_ptr_op(output, OP_EQ, NULL);
|
||||
|
||||
tor_free(addr_port);
|
||||
tor_free(output);
|
||||
|
||||
done:
|
||||
tor_free(addr_port);
|
||||
tor_free(output);
|
||||
}
|
||||
|
||||
struct testcase_t proto_haproxy_tests[] = {
|
||||
{ "format_proxy_header_line", test_format_proxy_header_line, 0, NULL, NULL },
|
||||
|
||||
END_OF_TESTCASES
|
||||
};
|
Loading…
Reference in New Issue
Block a user