[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [obfsproxy/master] Break up the listener callback by listener mode, and delay creating the output buffer in socks mode till we know where to connect
commit d0cf5ae1f52fc3bf9daa4c3fb754cc77e4b74159
Author: Zack Weinberg <zackw@xxxxxxxxx>
Date: Sun Jul 24 18:32:18 2011 -0700
Break up the listener callback by listener mode, and delay creating the output buffer in socks mode till we know where to connect
---
src/network.c | 227 +++++++++++++++++++++++++++++++++++++++++++--------------
src/network.h | 5 +-
2 files changed, 173 insertions(+), 59 deletions(-)
diff --git a/src/network.c b/src/network.c
index 75d90ef..32d14ee 100644
--- a/src/network.c
+++ b/src/network.c
@@ -40,7 +40,11 @@ static smartlist_t *connections;
connections and shutdowns when the last connection is closed. */
static int shutting_down=0;
-static void simple_listener_cb(struct evconnlistener *evcl,
+static void simple_client_listener_cb(struct evconnlistener *evcl,
+ evutil_socket_t fd, struct sockaddr *sourceaddr, int socklen, void *arg);
+static void socks_client_listener_cb(struct evconnlistener *evcl,
+ evutil_socket_t fd, struct sockaddr *sourceaddr, int socklen, void *arg);
+static void simple_server_listener_cb(struct evconnlistener *evcl,
evutil_socket_t fd, struct sockaddr *sourceaddr, int socklen, void *arg);
static void conn_free(conn_t *conn);
@@ -108,23 +112,29 @@ close_all_connections(void)
*/
listener_t *
listener_new(struct event_base *base,
- protocol_params_t *proto_params)
+ protocol_params_t *params)
{
const unsigned flags =
LEV_OPT_CLOSE_ON_FREE|LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_REUSEABLE;
-
+ evconnlistener_cb callback;
listener_t *lsn = xzalloc(sizeof(listener_t));
- lsn->proto_params = proto_params;
+ switch (params->mode) {
+ case LSN_SIMPLE_CLIENT: callback = simple_client_listener_cb; break;
+ case LSN_SIMPLE_SERVER: callback = simple_server_listener_cb; break;
+ case LSN_SOCKS_CLIENT: callback = socks_client_listener_cb; break;
+ default: obfs_abort();
+ }
+ lsn->proto_params = params;
lsn->listener =
- evconnlistener_new_bind(base, simple_listener_cb, lsn, flags, -1,
- proto_params->listen_addr->ai_addr,
- proto_params->listen_addr->ai_addrlen);
+ evconnlistener_new_bind(base, callback, lsn, flags, -1,
+ params->listen_addr->ai_addr,
+ params->listen_addr->ai_addrlen);
if (!lsn->listener) {
log_warn("Failed to create listener!");
- proto_params_free(lsn->proto_params);
+ proto_params_free(params);
free(lsn);
return NULL;
}
@@ -167,23 +177,22 @@ free_all_listeners(void)
}
/**
- This function is called when a new connection is received.
-
- It initializes the protocol we are using, sets up the necessary
- callbacks for input/output and does the protocol handshake.
+ This function is called when an upstream client connects to us in
+ simple client mode.
*/
static void
-simple_listener_cb(struct evconnlistener *evcl,
- evutil_socket_t fd, struct sockaddr *sourceaddr,
- int socklen, void *arg)
+simple_client_listener_cb(struct evconnlistener *evcl,
+ evutil_socket_t fd, struct sockaddr *sourceaddr,
+ int socklen, void *arg)
{
listener_t *lsn = arg;
struct event_base *base;
conn_t *conn = xzalloc(sizeof(conn_t));
- log_debug("Got a connection attempt.");
+ log_debug("%s: connection attempt.", __func__);
conn->mode = lsn->proto_params->mode;
+ obfs_assert(conn->mode == LSN_SIMPLE_CLIENT);
conn->proto = proto_create(lsn->proto_params);
if (!conn->proto) {
@@ -191,67 +200,161 @@ simple_listener_cb(struct evconnlistener *evcl,
goto err;
}
- if (conn->mode == LSN_SOCKS_CLIENT) {
- /* Construct SOCKS state. */
- conn->socks_state = socks_state_new();
+ /* New bufferevent to wrap socket we received. */
+ base = evconnlistener_get_base(lsn->listener);
+ conn->input = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
+ if (!conn->input)
+ goto err;
+ fd = -1; /* prevent double-close */
+
+ /* New bufferevent to connect to the target address */
+ conn->output = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
+ if (!conn->output)
+ goto err;
+
+ bufferevent_setcb(conn->input, plaintext_read_cb, NULL, input_event_cb, conn);
+ bufferevent_enable(conn->input, EV_READ|EV_WRITE);
+
+ bufferevent_setcb(conn->output,
+ obfuscated_read_cb, NULL, output_event_cb, conn);
+
+ /* Queue output right now. */
+ if (proto_handshake(conn->proto, bufferevent_get_output(conn->output)) < 0)
+ goto err;
+
+ /* Launch the connect attempt. */
+ if (bufferevent_socket_connect(conn->output,
+ lsn->proto_params->target_addr->ai_addr,
+ lsn->proto_params->target_addr->ai_addrlen)<0)
+ goto err;
+
+ bufferevent_enable(conn->output, EV_READ|EV_WRITE);
+
+ /* add conn to the connection list */
+ if (!connections)
+ connections = smartlist_create();
+ smartlist_add(connections, conn);
+
+ log_debug("%s: setup completed, %d connections",
+ __func__, smartlist_len(connections));
+ return;
+
+ err:
+ if (conn)
+ conn_free(conn);
+ if (fd >= 0)
+ evutil_closesocket(fd);
+}
+
+/**
+ This function is called when an upstream client connects to us in
+ socks mode.
+*/
+static void
+socks_client_listener_cb(struct evconnlistener *evcl,
+ evutil_socket_t fd, struct sockaddr *sourceaddr,
+ int socklen, void *arg)
+{
+ listener_t *lsn = arg;
+ struct event_base *base;
+ conn_t *conn = xzalloc(sizeof(conn_t));
+
+ log_debug("%s: connection attempt.", __func__);
+
+ conn->mode = lsn->proto_params->mode;
+ obfs_assert(conn->mode == LSN_SOCKS_CLIENT);
+
+ conn->proto = proto_create(lsn->proto_params);
+ if (!conn->proto) {
+ log_warn("Creation of protocol object failed! Closing connection.");
+ goto err;
}
+ /* Construct SOCKS state. */
+ conn->socks_state = socks_state_new();
+
/* New bufferevent to wrap socket we received. */
base = evconnlistener_get_base(lsn->listener);
- conn->input = bufferevent_socket_new(base,
- fd,
- BEV_OPT_CLOSE_ON_FREE);
+ conn->input = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
if (!conn->input)
goto err;
fd = -1; /* prevent double-close */
- if (conn->mode == LSN_SIMPLE_SERVER) {
- bufferevent_setcb(conn->input,
- obfuscated_read_cb, NULL, input_event_cb, conn);
- } else if (conn->mode == LSN_SIMPLE_CLIENT) {
- bufferevent_setcb(conn->input,
- plaintext_read_cb, NULL, input_event_cb, conn);
- } else {
- obfs_assert(conn->mode == LSN_SOCKS_CLIENT);
- bufferevent_setcb(conn->input,
- socks_read_cb, NULL, input_event_cb, conn);
+ bufferevent_setcb(conn->input, socks_read_cb, NULL, input_event_cb, conn);
+ bufferevent_enable(conn->input, EV_READ|EV_WRITE);
+
+ /* Do not create a target bufferevent at this time; the socks
+ handler will do it after we know where we're connecting */
+
+ /* add conn to the connection list */
+ if (!connections)
+ connections = smartlist_create();
+ smartlist_add(connections, conn);
+
+ log_debug("%s: setup completed, %d connections",
+ __func__, smartlist_len(connections));
+ return;
+
+ err:
+ if (conn)
+ conn_free(conn);
+ if (fd >= 0)
+ evutil_closesocket(fd);
+}
+
+/**
+ This function is called when a remote client connects to us in
+ server mode.
+*/
+static void
+simple_server_listener_cb(struct evconnlistener *evcl,
+ evutil_socket_t fd, struct sockaddr *sourceaddr,
+ int socklen, void *arg)
+{
+ listener_t *lsn = arg;
+ struct event_base *base;
+ conn_t *conn = xzalloc(sizeof(conn_t));
+
+ log_debug("%s: connection attempt.", __func__);
+
+ conn->mode = lsn->proto_params->mode;
+ obfs_assert(conn->mode == LSN_SIMPLE_SERVER);
+
+ conn->proto = proto_create(lsn->proto_params);
+ if (!conn->proto) {
+ log_warn("Creation of protocol object failed! Closing connection.");
+ goto err;
}
+ /* New bufferevent to wrap socket we received. */
+ base = evconnlistener_get_base(lsn->listener);
+ conn->input = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
+ if (!conn->input)
+ goto err;
+ fd = -1; /* prevent double-close */
+
+ bufferevent_setcb(conn->input, obfuscated_read_cb, NULL, input_event_cb, conn);
bufferevent_enable(conn->input, EV_READ|EV_WRITE);
/* New bufferevent to connect to the target address */
- conn->output = bufferevent_socket_new(base,
- -1,
- BEV_OPT_CLOSE_ON_FREE);
+ conn->output = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
if (!conn->output)
goto err;
- if (conn->mode == LSN_SIMPLE_SERVER)
- bufferevent_setcb(conn->output,
- plaintext_read_cb, NULL, output_event_cb, conn);
- else
- bufferevent_setcb(conn->output,
- obfuscated_read_cb, NULL, output_event_cb, conn);
-
- /* Queue output right now. */
- struct bufferevent *encrypted =
- conn->mode == LSN_SIMPLE_SERVER ? conn->input : conn->output;
+ bufferevent_setcb(conn->output, plaintext_read_cb, NULL,
+ output_event_cb, conn);
- /* ASN Will all protocols need to handshake here? Don't think so. */
+ /* Queue handshake, if any, before connecting. */
if (proto_handshake(conn->proto,
- bufferevent_get_output(encrypted))<0)
+ bufferevent_get_output(conn->input))<0)
goto err;
- if (conn->mode == LSN_SIMPLE_SERVER || conn->mode == LSN_SIMPLE_CLIENT) {
- /* Launch the connect attempt. */
- if (bufferevent_socket_connect(conn->output,
- lsn->proto_params->target_addr->ai_addr,
- lsn->proto_params->target_addr->ai_addrlen)
- < 0)
- goto err;
+ if (bufferevent_socket_connect(conn->output,
+ lsn->proto_params->target_addr->ai_addr,
+ lsn->proto_params->target_addr->ai_addrlen)<0)
+ goto err;
- bufferevent_enable(conn->output, EV_READ|EV_WRITE);
- }
+ bufferevent_enable(conn->output, EV_READ|EV_WRITE);
/* add conn to the connection list */
if (!connections)
@@ -346,6 +449,18 @@ socks_read_cb(struct bufferevent *bev, void *arg)
const char *addr=NULL;
r = socks_state_get_address(conn->socks_state, &af, &addr, &port);
obfs_assert(r==0);
+ conn->output = bufferevent_socket_new(bufferevent_get_base(conn->input),
+ -1,
+ BEV_OPT_CLOSE_ON_FREE);
+
+ /* queue handshake, if any, before connecting */
+ if (proto_handshake(conn->proto,
+ bufferevent_get_output(conn->output))<0) {
+ /* XXXX send socks reply */
+ close_conn(conn);
+ return;
+ }
+
r = bufferevent_socket_connect_hostname(conn->output,
get_evdns_base(),
af, addr, port);
diff --git a/src/network.h b/src/network.h
index 7ba9afc..49580c3 100644
--- a/src/network.h
+++ b/src/network.h
@@ -43,12 +43,11 @@ struct socks_state_t;
struct protocol_t;
typedef struct conn_t {
+ struct protocol_t *proto;
struct socks_state_t *socks_state;
- struct protocol_t *proto; /* ASN Do we like this here? We probably don't.
- But it's so convenient!! So convenient! */
- int mode;
struct bufferevent *input;
struct bufferevent *output;
+ unsigned int mode : 30;
unsigned int flushing : 1;
unsigned int is_open : 1;
} conn_t;
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits