commit 119004e87d6303de5e90e7dfad87dd89bae6bd5f Author: Suphanat Chunhapanya haxx.pop@gmail.com Date: Fri Aug 23 11:44:49 2019 +0800
circuit: Implement haproxy --- src/core/include.am | 2 ++ src/core/mainloop/connection.c | 48 +++++++++++++++++++++++++++++- src/core/mainloop/connection.h | 4 ++- src/core/or/connection_or.c | 15 +++++++++- src/core/or/or.h | 5 ++-- src/core/or/or_connection_st.h | 2 +- src/core/proto/.may_include | 6 +++- src/core/proto/proto_haproxy.c | 45 ++++++++++++++++++++++++++++ src/core/proto/proto_haproxy.h | 12 ++++++++ src/feature/control/btrack_orconn_cevent.c | 1 + 10 files changed, 133 insertions(+), 7 deletions(-)
diff --git a/src/core/include.am b/src/core/include.am index 9b4b251c8..8f455c177 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 c135bf395..de91b93cb 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 c93f1ef8e..2ebb053cc 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 4c93351e3..d9db17ef7 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 990cfacbc..9a7a9cc4b 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 051fcd00d..ae94b42cd 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 c1647a5cf..a66c3f83a 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 000000000..856f2ab15 --- /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 000000000..fd4240f5d --- /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 535aa8f61..d4ba7f79a 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;
tor-commits@lists.torproject.org