[tor-commits] [tor/master] circuit: Refactor connection_proxy_connect

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


commit 52e59640f9ae266d25a7727869c84e506c96a1c8
Author: Suphanat Chunhapanya <haxx.pop at gmail.com>
Date:   Fri Aug 23 10:35:50 2019 +0800

    circuit: Refactor connection_proxy_connect
    
    Since connection_proxy_connect is too long now, it's better to create
    new functions (connection_https_proxy_connect,
    connection_socks4_proxy_connect, and connection_socks5_proxy_connect) to
    make connection_proxy_connect shorter.
---
 src/core/mainloop/connection.c | 293 ++++++++++++++++++++++++-----------------
 1 file changed, 170 insertions(+), 123 deletions(-)

diff --git a/src/core/mainloop/connection.c b/src/core/mainloop/connection.c
index 6094f33e4..c135bf395 100644
--- a/src/core/mainloop/connection.c
+++ b/src/core/mainloop/connection.c
@@ -2326,165 +2326,212 @@ 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.
- *
- * Use connection_read_proxy_handshake() to complete the handshake.
  */
-int
-connection_proxy_connect(connection_t *conn, int type)
+static int
+connection_https_proxy_connect(connection_t *conn)
 {
-  const or_options_t *options;
+  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);
 
-  options = get_options();
+  unsigned char *buf;
+  uint16_t portn;
+  uint32_t ip4addr;
+  size_t buf_size = 0;
+  char *socks_args_string = NULL;
 
-  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");
-      }
+  /* Send a SOCKS4 connect request */
 
-      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));
-      }
+  if (tor_addr_family(&conn->addr) != AF_INET) {
+    log_warn(LD_NET, "SOCKS4 client is incompatible with IPv6");
+    return -1;
+  }
 
-      connection_buf_add(buf, strlen(buf), conn);
-      conn->proxy_state = PROXY_HTTPS_WANT_CONNECT_OK;
-      break;
+  { /* 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);
     }
+  }
 
-    case PROXY_SOCKS4: {
-      unsigned char *buf;
-      uint16_t portn;
-      uint32_t ip4addr;
-      size_t buf_size = 0;
-      char *socks_args_string = NULL;
+  { /* Figure out the buffer size we need for the SOCKS message: */
 
-      /* Send a SOCKS4 connect request */
+    buf_size = SOCKS4_STANDARD_BUFFER_SIZE;
 
-      if (tor_addr_family(&conn->addr) != AF_INET) {
-        log_warn(LD_NET, "SOCKS4 client is incompatible with IPv6");
-        return -1;
-      }
+    /* 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);
+  }
 
-      { /* 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': */
+  buf = tor_malloc_zero(buf_size);
 
-        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);
-        }
-      }
+  ip4addr = tor_addr_to_ipv4n(&conn->addr);
+  portn = htons(conn->port);
 
-      { /* Figure out the buffer size we need for the SOCKS message: */
+  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 */
+  }
 
-        buf_size = SOCKS4_STANDARD_BUFFER_SIZE;
+  connection_buf_add((char *)buf, buf_size, conn);
+  tor_free(buf);
 
-        /* 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);
-      }
+  conn->proxy_state = PROXY_SOCKS4_WANT_CONNECT_OK;
+  return 0;
+}
 
-      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 */
-      }
+/** 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);
 
-      connection_buf_add((char *)buf, buf_size, conn);
-      tor_free(buf);
+  const or_options_t *options = get_options();
+  unsigned char buf[4]; /* fields: vers, num methods, method list */
 
-      conn->proxy_state = PROXY_SOCKS4_WANT_CONNECT_OK;
-      break;
-    }
+  /* Send a SOCKS5 greeting (connect request must wait) */
 
-    case PROXY_SOCKS5: {
-      unsigned char buf[4]; /* fields: vers, num methods, method list */
+  buf[0] = 5; /* version */
 
-      /* Send a SOCKS5 greeting (connect request must wait) */
+  /* 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;
+  }
 
-      buf[0] = 5; /* version */
+  connection_buf_add((char *)buf, 2 + buf[1], conn);
+  return 0;
+}
 
-      /* 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;
-      }
+/** 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.
+ *
+ * Use connection_read_proxy_handshake() to complete the handshake.
+ */
+int
+connection_proxy_connect(connection_t *conn, int type)
+{
+  int ret = 0;
+
+  tor_assert(conn);
 
-      connection_buf_add((char *)buf, 2 + buf[1], conn);
+  switch (type) {
+    case PROXY_CONNECT:
+      ret = connection_https_proxy_connect(conn);
+      break;
+
+    case PROXY_SOCKS4:
+      ret = connection_socks4_proxy_connect(conn);
+      break;
+
+    case PROXY_SOCKS5:
+      ret = connection_socks5_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





More information about the tor-commits mailing list