[tor-commits] [tor/master] circuit: Implement haproxy

nickm at torproject.org nickm at torproject.org
Mon Jan 6 22:28:00 UTC 2020


commit 119004e87d6303de5e90e7dfad87dd89bae6bd5f
Author: Suphanat Chunhapanya <haxx.pop at 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;





More information about the tor-commits mailing list