commit 52e59640f9ae266d25a7727869c84e506c96a1c8 Author: Suphanat Chunhapanya haxx.pop@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
tor-commits@lists.torproject.org