mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-10 13:13:44 +01:00
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.
This commit is contained in:
parent
101bdeb02d
commit
52e59640f9
@ -2326,10 +2326,173 @@ 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.
|
||||
*/
|
||||
static int
|
||||
connection_https_proxy_connect(connection_t *conn)
|
||||
{
|
||||
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);
|
||||
|
||||
unsigned char *buf;
|
||||
uint16_t portn;
|
||||
uint32_t ip4addr;
|
||||
size_t buf_size = 0;
|
||||
char *socks_args_string = NULL;
|
||||
|
||||
/* Send a SOCKS4 connect request */
|
||||
|
||||
if (tor_addr_family(&conn->addr) != AF_INET) {
|
||||
log_warn(LD_NET, "SOCKS4 client is incompatible with IPv6");
|
||||
return -1;
|
||||
}
|
||||
|
||||
{ /* 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);
|
||||
}
|
||||
}
|
||||
|
||||
{ /* Figure out the buffer size we need for the SOCKS message: */
|
||||
|
||||
buf_size = SOCKS4_STANDARD_BUFFER_SIZE;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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 */
|
||||
}
|
||||
|
||||
connection_buf_add((char *)buf, buf_size, conn);
|
||||
tor_free(buf);
|
||||
|
||||
conn->proxy_state = PROXY_SOCKS4_WANT_CONNECT_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** 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);
|
||||
|
||||
const or_options_t *options = get_options();
|
||||
unsigned char buf[4]; /* fields: vers, num methods, method list */
|
||||
|
||||
/* Send a SOCKS5 greeting (connect request must wait) */
|
||||
|
||||
buf[0] = 5; /* version */
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
connection_buf_add((char *)buf, 2 + buf[1], conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** 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.
|
||||
@ -2339,152 +2502,36 @@ conn_get_proxy_type(const connection_t *conn)
|
||||
int
|
||||
connection_proxy_connect(connection_t *conn, int type)
|
||||
{
|
||||
const or_options_t *options;
|
||||
int ret = 0;
|
||||
|
||||
tor_assert(conn);
|
||||
|
||||
options = get_options();
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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;
|
||||
case PROXY_CONNECT:
|
||||
ret = connection_https_proxy_connect(conn);
|
||||
break;
|
||||
}
|
||||
|
||||
case PROXY_SOCKS4: {
|
||||
unsigned char *buf;
|
||||
uint16_t portn;
|
||||
uint32_t ip4addr;
|
||||
size_t buf_size = 0;
|
||||
char *socks_args_string = NULL;
|
||||
|
||||
/* Send a SOCKS4 connect request */
|
||||
|
||||
if (tor_addr_family(&conn->addr) != AF_INET) {
|
||||
log_warn(LD_NET, "SOCKS4 client is incompatible with IPv6");
|
||||
return -1;
|
||||
}
|
||||
|
||||
{ /* 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);
|
||||
}
|
||||
}
|
||||
|
||||
{ /* Figure out the buffer size we need for the SOCKS message: */
|
||||
|
||||
buf_size = SOCKS4_STANDARD_BUFFER_SIZE;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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 */
|
||||
}
|
||||
|
||||
connection_buf_add((char *)buf, buf_size, conn);
|
||||
tor_free(buf);
|
||||
|
||||
conn->proxy_state = PROXY_SOCKS4_WANT_CONNECT_OK;
|
||||
case PROXY_SOCKS4:
|
||||
ret = connection_socks4_proxy_connect(conn);
|
||||
break;
|
||||
}
|
||||
|
||||
case PROXY_SOCKS5: {
|
||||
unsigned char buf[4]; /* fields: vers, num methods, method list */
|
||||
|
||||
/* Send a SOCKS5 greeting (connect request must wait) */
|
||||
|
||||
buf[0] = 5; /* version */
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
connection_buf_add((char *)buf, 2 + buf[1], conn);
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user