Skip to content
Snippets Groups Projects
Commit 9796b9bf authored by Nick Mathewson's avatar Nick Mathewson :game_die:
Browse files

Implement SOCKS-client support for bufferevents

parent c74a4ab5
No related branches found
No related tags found
No related merge requests found
......@@ -56,6 +56,9 @@
static int parse_socks(const char *data, size_t datalen, socks_request_t *req,
int log_sockstype, int safe_socks, ssize_t *drain_out,
size_t *want_length_out);
static int parse_socks_client(const uint8_t *data, size_t datalen,
int state, char **reason,
ssize_t *drain_out);
/* Chunk manipulation functions */
......@@ -1513,7 +1516,7 @@ fetch_from_evbuffer_socks(struct evbuffer *buf, socks_request_t *req,
want_length = evbuffer_get_contiguous_space(buf);
n_drain = 0;
i = evbuffer_peek(buf, want_length, NULL, &v, 1);
tor_assert(i == i);
tor_assert(i == 1);
data = v.iov_base;
datalen = v.iov_len;
......@@ -1900,21 +1903,61 @@ parse_socks(const char *data, size_t datalen, socks_request_t *req,
int
fetch_from_buf_socks_client(buf_t *buf, int state, char **reason)
{
unsigned char *data;
size_t addrlen;
ssize_t drain = 0;
int r;
if (buf->datalen < 2)
return 0;
buf_pullup(buf, 128, 0);
tor_assert(buf->head && buf->head->datalen >= 2);
data = (unsigned char *) buf->head->data;
r = parse_socks_client((uint8_t*)buf->head->data, buf->head->datalen,
state, reason, &drain);
if (drain > 0)
buf_remove_from_front(buf, drain);
else if (drain < 0)
buf_clear(buf);
return r;
}
#ifdef USE_BUFFEREVENTS
/** As fetch_from_buf_socks_client, buf works on an evbuffer */
int
fetch_from_evbuffer_socks_client(struct evbuffer *buf, int state,
char **reason)
{
ssize_t drain = 0;
uint8_t *data;
size_t datalen = evbuffer_get_contiguous_space(buf);
int r;
data = evbuffer_pullup(buf, 128);
r = parse_socks_client(data, datalen, state, reason, &drain);
if (drain > 0)
evbuffer_drain(buf, drain);
else
evbuffer_drain(buf, evbuffer_get_length(buf));
return r;
}
#endif
/** Implementation logic for fetch_from_*_socks_client. */
static int
parse_socks_client(const uint8_t *data, size_t datalen,
int state, char **reason,
ssize_t *drain_out)
{
unsigned int addrlen;
*drain_out = 0;
if (datalen < 2)
return 0;
switch (state) {
case PROXY_SOCKS4_WANT_CONNECT_OK:
/* Wait for the complete response */
if (buf->head->datalen < 8)
if (datalen < 8)
return 0;
if (data[1] != 0x5a) {
......@@ -1923,7 +1966,7 @@ fetch_from_buf_socks_client(buf_t *buf, int state, char **reason)
}
/* Success */
buf_remove_from_front(buf, 8);
*drain_out = 8;
return 1;
case PROXY_SOCKS5_WANT_AUTH_METHOD_NONE:
......@@ -1935,7 +1978,7 @@ fetch_from_buf_socks_client(buf_t *buf, int state, char **reason)
}
log_info(LD_NET, "SOCKS 5 client: continuing without authentication");
buf_clear(buf);
*drain_out = -1;
return 1;
case PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929:
......@@ -1945,11 +1988,11 @@ fetch_from_buf_socks_client(buf_t *buf, int state, char **reason)
case 0x00:
log_info(LD_NET, "SOCKS 5 client: we have auth details but server "
"doesn't require authentication.");
buf_clear(buf);
*drain_out = -1;
return 1;
case 0x02:
log_info(LD_NET, "SOCKS 5 client: need authentication.");
buf_clear(buf);
*drain_out = -1;
return 2;
/* fall through */
}
......@@ -1966,7 +2009,7 @@ fetch_from_buf_socks_client(buf_t *buf, int state, char **reason)
}
log_info(LD_NET, "SOCKS 5 client: authentication successful.");
buf_clear(buf);
*drain_out = -1;
return 1;
case PROXY_SOCKS5_WANT_CONNECT_OK:
......@@ -1975,7 +2018,7 @@ fetch_from_buf_socks_client(buf_t *buf, int state, char **reason)
* the data used */
/* wait for address type field to arrive */
if (buf->datalen < 4)
if (datalen < 4)
return 0;
switch (data[3]) {
......@@ -1986,7 +2029,7 @@ fetch_from_buf_socks_client(buf_t *buf, int state, char **reason)
addrlen = 16;
break;
case 0x03: /* fqdn (can this happen here?) */
if (buf->datalen < 5)
if (datalen < 5)
return 0;
addrlen = 1 + data[4];
break;
......@@ -1996,7 +2039,7 @@ fetch_from_buf_socks_client(buf_t *buf, int state, char **reason)
}
/* wait for address and port */
if (buf->datalen < 6 + addrlen)
if (datalen < 6 + addrlen)
return 0;
if (data[1] != 0x00) {
......@@ -2004,7 +2047,7 @@ fetch_from_buf_socks_client(buf_t *buf, int state, char **reason)
return -1;
}
buf_remove_from_front(buf, 6 + addrlen);
*drain_out = 6 + addrlen;
return 1;
}
......
......@@ -53,6 +53,8 @@ int fetch_var_cell_from_evbuffer(struct evbuffer *buf, var_cell_t **out,
int linkproto);
int fetch_from_evbuffer_socks(struct evbuffer *buf, socks_request_t *req,
int log_sockstype, int safe_socks);
int fetch_from_evbuffer_socks_client(struct evbuffer *buf, int state,
char **reason);
int fetch_from_evbuffer_http(struct evbuffer *buf,
char **headers_out, size_t max_headerlen,
char **body_out, size_t *body_used, size_t max_bodylen,
......
......@@ -1572,6 +1572,19 @@ connection_send_socks5_connect(connection_t *conn)
conn->proxy_state = PROXY_SOCKS5_WANT_CONNECT_OK;
}
/** DOCDOC */
static int
connection_fetch_from_buf_socks_client(connection_t *conn,
int state, char **reason)
{
IF_HAS_BUFFEREVENT(conn, {
struct evbuffer *input = bufferevent_get_input(conn->bufev);
return fetch_from_evbuffer_socks_client(input, state, reason);
}) ELSE_IF_NO_BUFFEREVENT {
return fetch_from_buf_socks_client(conn->inbuf, state, reason);
}
}
/** Call this from connection_*_process_inbuf() to advance the proxy
* handshake.
*
......@@ -1599,17 +1612,17 @@ connection_read_proxy_handshake(connection_t *conn)
break;
case PROXY_SOCKS4_WANT_CONNECT_OK:
ret = fetch_from_buf_socks_client(conn->inbuf,
conn->proxy_state,
&reason);
ret = connection_fetch_from_buf_socks_client(conn,
conn->proxy_state,
&reason);
if (ret == 1)
conn->proxy_state = PROXY_CONNECTED;
break;
case PROXY_SOCKS5_WANT_AUTH_METHOD_NONE:
ret = fetch_from_buf_socks_client(conn->inbuf,
conn->proxy_state,
&reason);
ret = connection_fetch_from_buf_socks_client(conn,
conn->proxy_state,
&reason);
/* no auth needed, do connect */
if (ret == 1) {
connection_send_socks5_connect(conn);
......@@ -1618,9 +1631,9 @@ connection_read_proxy_handshake(connection_t *conn)
break;
case PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929:
ret = fetch_from_buf_socks_client(conn->inbuf,
conn->proxy_state,
&reason);
ret = connection_fetch_from_buf_socks_client(conn,
conn->proxy_state,
&reason);
/* send auth if needed, otherwise do connect */
if (ret == 1) {
......@@ -1655,9 +1668,9 @@ connection_read_proxy_handshake(connection_t *conn)
break;
case PROXY_SOCKS5_WANT_AUTH_RFC1929_OK:
ret = fetch_from_buf_socks_client(conn->inbuf,
conn->proxy_state,
&reason);
ret = connection_fetch_from_buf_socks_client(conn,
conn->proxy_state,
&reason);
/* send the connect request */
if (ret == 1) {
connection_send_socks5_connect(conn);
......@@ -1666,9 +1679,9 @@ connection_read_proxy_handshake(connection_t *conn)
break;
case PROXY_SOCKS5_WANT_CONNECT_OK:
ret = fetch_from_buf_socks_client(conn->inbuf,
conn->proxy_state,
&reason);
ret = connection_fetch_from_buf_socks_client(conn,
conn->proxy_state,
&reason);
if (ret == 1)
conn->proxy_state = PROXY_CONNECTED;
break;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment