aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSuphanat Chunhapanya <haxx.pop@gmail.com>2019-08-23 11:44:49 +0800
committerNick Mathewson <nickm@torproject.org>2020-01-06 13:39:10 -0500
commit119004e87d6303de5e90e7dfad87dd89bae6bd5f (patch)
tree478992107e48b6a44537a867aeba3412788b8706
parent52e59640f9ae266d25a7727869c84e506c96a1c8 (diff)
downloadtor-119004e87d6303de5e90e7dfad87dd89bae6bd5f.tar.gz
tor-119004e87d6303de5e90e7dfad87dd89bae6bd5f.zip
circuit: Implement haproxy
-rw-r--r--src/core/include.am2
-rw-r--r--src/core/mainloop/connection.c48
-rw-r--r--src/core/mainloop/connection.h4
-rw-r--r--src/core/or/connection_or.c15
-rw-r--r--src/core/or/or.h5
-rw-r--r--src/core/or/or_connection_st.h2
-rw-r--r--src/core/proto/.may_include6
-rw-r--r--src/core/proto/proto_haproxy.c45
-rw-r--r--src/core/proto/proto_haproxy.h12
-rw-r--r--src/feature/control/btrack_orconn_cevent.c1
10 files changed, 133 insertions, 7 deletions
diff --git a/src/core/include.am b/src/core/include.am
index 9b4b251c81..8f455c1773 100644
--- a/src/core/include.am
+++ b/src/core/include.am
@@ -63,6 +63,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 \
@@ -295,6 +296,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 \
diff --git a/src/core/mainloop/connection.c b/src/core/mainloop/connection.c
index c135bf3959..de91b93cb6 100644
--- a/src/core/mainloop/connection.c
+++ b/src/core/mainloop/connection.c
@@ -83,6 +83,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"
@@ -2317,7 +2318,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;
}
@@ -2489,6 +2494,35 @@ connection_socks5_proxy_connect(connection_t *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
@@ -2519,6 +2553,10 @@ connection_proxy_connect(connection_t *conn, int type)
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();
@@ -5498,6 +5536,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);
@@ -5535,6 +5580,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);
diff --git a/src/core/mainloop/connection.h b/src/core/mainloop/connection.h
index c93f1ef8e8..2ebb053cca 100644
--- a/src/core/mainloop/connection.h
+++ b/src/core/mainloop/connection.h
@@ -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
diff --git a/src/core/or/connection_or.c b/src/core/or/connection_or.c
index 4c93351e31..d9db17ef77 100644
--- a/src/core/or/connection_or.c
+++ b/src/core/or/connection_or.c
@@ -726,6 +726,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 +777,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;
}
diff --git a/src/core/or/or.h b/src/core/or/or.h
index 990cfacbc0..9a7a9cc4b7 100644
--- a/src/core/or/or.h
+++ b/src/core/or/or.h
@@ -168,12 +168,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? */
diff --git a/src/core/or/or_connection_st.h b/src/core/or/or_connection_st.h
index 051fcd00d3..ae94b42cd9 100644
--- a/src/core/or/or_connection_st.h
+++ b/src/core/or/or_connection_st.h
@@ -58,7 +58,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. */
diff --git a/src/core/proto/.may_include b/src/core/proto/.may_include
index c1647a5cf9..a66c3f83a6 100644
--- a/src/core/proto/.may_include
+++ b/src/core/proto/.may_include
@@ -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 \ No newline at end of file
+core/proto/*.h
diff --git a/src/core/proto/proto_haproxy.c b/src/core/proto/proto_haproxy.c
new file mode 100644
index 0000000000..856f2ab152
--- /dev/null
+++ b/src/core/proto/proto_haproxy.c
@@ -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;
+}
diff --git a/src/core/proto/proto_haproxy.h b/src/core/proto/proto_haproxy.h
new file mode 100644
index 0000000000..fd4240f5dd
--- /dev/null
+++ b/src/core/proto/proto_haproxy.h
@@ -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) */
diff --git a/src/feature/control/btrack_orconn_cevent.c b/src/feature/control/btrack_orconn_cevent.c
index 535aa8f614..d4ba7f79a1 100644
--- a/src/feature/control/btrack_orconn_cevent.c
+++ b/src/feature/control/btrack_orconn_cevent.c
@@ -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;