tor-commits
Threads by month
- ----- 2026 -----
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- 1 participants
- 216095 discussions
[obfsproxy/master] A conn_t now wraps only one socket. A new struct, circuit_t, associates the two sides of a proxy channel.
by nickm@torproject.org 09 Sep '11
by nickm@torproject.org 09 Sep '11
09 Sep '11
commit 99dee61ff3aa70aab43b9543a8fd0c58858f0dcd
Author: Zack Weinberg <zackw(a)panix.com>
Date: Wed Aug 3 11:20:17 2011 -0700
A conn_t now wraps only one socket. A new struct, circuit_t, associates the two sides of a proxy channel.
---
src/network.c | 538 ++++++++++++++++++++++++++++++++------------------------
src/network.h | 32 +++-
src/util.h | 1 +
3 files changed, 331 insertions(+), 240 deletions(-)
diff --git a/src/network.c b/src/network.c
index 4ae2c15..08ce696 100644
--- a/src/network.c
+++ b/src/network.c
@@ -20,25 +20,27 @@
/* Terminology used in this file:
- A "side" is a bidirectional communications channel, usually backed
- by a network socket and represented at this layer by a
- 'struct bufferevent'.
-
- A "connection" is a _pair_ of sides, referred to as the "upstream"
- side and the "downstream" side. A connection is represented by a
- 'conn_t'. The upstream side of a connection communicates in
- cleartext with the higher-level program that wishes to make use of
- our obfuscation service. The downstream side commmunicates in an
- obfuscated fashion with the remote peer that the higher-level
- client wishes to contact.
+ A "connection" is a bidirectional communications channel, usually
+ backed by a network socket, and represented in this layer by a
+ 'conn_t', wrapping a 'struct bufferevent'.
+
+ A "circuit" is a _pair_ of connections, referred to as the
+ "upstream" and "downstream" connections. A circuit is represented
+ by a 'circuit_t'. The upstream connection of a circuit
+ communicates in cleartext with the higher-level program that wishes
+ to make use of our obfuscation service. The downstream connection
+ commmunicates in an obfuscated fashion with the remote peer that
+ the higher-level client wishes to contact.
A "listener" is a listening socket bound to a particular
- obfuscation protocol, represented in this layer by a 'listener_t'.
- Connecting to a listener creates one side of a connection, and
- causes this program to initiate the other side of the connection.
- A listener is said to be a "client" listener if connecting to it
- creates the _upstream_ side of a connection, and a "server"
- listener if connecting to it creates the _downstream_ side.
+ obfuscation protocol, represented in this layer by a 'listener_t'
+ and its 'config_t'. Connecting to a listener creates one
+ connection of a circuit, and causes this program to initiate the
+ other connection (possibly after receiving in-band instructions
+ about where to connect to). A listener is said to be a "client"
+ listener if connecting to it creates the _upstream_ connection, and
+ a "server" listener if connecting to it creates the _downstream_
+ connection.
There are two kinds of client listeners: a "simple" client listener
always connects to the same remote peer every time it needs to
@@ -72,19 +74,17 @@ static void listener_cb(struct evconnlistener *evcl, evutil_socket_t fd,
struct sockaddr *sourceaddr, int socklen,
void *closure);
-static void simple_client_listener_cb(conn_t *conn, struct bufferevent *buf);
-static void socks_client_listener_cb(conn_t *conn, struct bufferevent *buf);
-static void simple_server_listener_cb(conn_t *conn, struct bufferevent *buf);
+static void simple_client_listener_cb(conn_t *conn);
+static void socks_client_listener_cb(conn_t *conn);
+static void simple_server_listener_cb(conn_t *conn);
static void conn_free(conn_t *conn);
-static void close_conn(conn_t *conn);
-static void close_all_connections(void);
+static void conn_free_all(void);
+static void conn_free_on_flush(struct bufferevent *bev, void *arg);
-static void close_conn_on_flush(struct bufferevent *bev, void *arg);
-
-static struct bufferevent *open_outbound_socket(conn_t *conn,
- struct event_base *base,
- bufferevent_data_cb readcb);
+static int circuit_create(conn_t *upstream, conn_t *downstream);
+static void circuit_free(circuit_t *circuit);
+static conn_t *open_outbound(conn_t *conn, bufferevent_data_cb readcb);
static void upstream_read_cb(struct bufferevent *bev, void *arg);
static void downstream_read_cb(struct bufferevent *bev, void *arg);
@@ -114,7 +114,7 @@ start_shutdown(int barbaric)
shutting_down=1;
if (barbaric)
- close_all_connections();
+ conn_free_all();
if (connections && smartlist_len(connections) == 0) {
smartlist_free(connections);
@@ -129,7 +129,7 @@ start_shutdown(int barbaric)
Closes all open connections.
*/
static void
-close_all_connections(void)
+conn_free_all(void)
{
if (!connections)
return;
@@ -251,10 +251,11 @@ listener_cb(struct evconnlistener *evcl, evutil_socket_t fd,
smartlist_len(connections));
conn->peername = peername;
+ conn->buffer = buf;
switch (conn->mode) {
- case LSN_SIMPLE_CLIENT: simple_client_listener_cb(conn, buf); break;
- case LSN_SOCKS_CLIENT: socks_client_listener_cb(conn, buf); break;
- case LSN_SIMPLE_SERVER: simple_server_listener_cb(conn, buf); break;
+ case LSN_SIMPLE_CLIENT: simple_client_listener_cb(conn); break;
+ case LSN_SOCKS_CLIENT: socks_client_listener_cb(conn); break;
+ case LSN_SIMPLE_SERVER: simple_server_listener_cb(conn); break;
default:
obfs_abort();
}
@@ -265,23 +266,16 @@ listener_cb(struct evconnlistener *evcl, evutil_socket_t fd,
simple client mode.
*/
static void
-simple_client_listener_cb(conn_t *conn, struct bufferevent *buf)
+simple_client_listener_cb(conn_t *conn)
{
- struct event_base *base = bufferevent_get_base(buf);
- obfs_assert(buf);
obfs_assert(conn);
obfs_assert(conn->mode == LSN_SIMPLE_CLIENT);
log_debug("%s: simple client connection", conn->peername);
- conn->upstream = buf;
- bufferevent_setcb(conn->upstream, upstream_read_cb, NULL, error_cb, conn);
-
- /* Don't enable the upstream side for reading at this point; wait
- till the downstream side is established. */
+ bufferevent_setcb(conn->buffer, upstream_read_cb, NULL, error_cb, conn);
- conn->downstream = open_outbound_socket(conn, base, downstream_read_cb);
- if (!conn->downstream) {
- close_conn(conn);
+ if (circuit_create(conn, open_outbound(conn, downstream_read_cb))) {
+ conn_free(conn);
return;
}
@@ -293,22 +287,19 @@ simple_client_listener_cb(conn_t *conn, struct bufferevent *buf)
socks mode.
*/
static void
-socks_client_listener_cb(conn_t *conn, struct bufferevent *buf)
+socks_client_listener_cb(conn_t *conn)
{
- obfs_assert(buf);
obfs_assert(conn);
obfs_assert(conn->mode == LSN_SOCKS_CLIENT);
log_debug("%s: socks client connection", conn->peername);
- conn->upstream = buf;
- bufferevent_setcb(conn->upstream, socks_read_cb, NULL, error_cb, conn);
- bufferevent_enable(conn->upstream, EV_READ|EV_WRITE);
-
- /* Construct SOCKS state. */
conn->socks_state = socks_state_new();
- /* Do not create a downstream bufferevent at this time; the socks
- handler will do it after it learns the downstream peer address. */
+ bufferevent_setcb(conn->buffer, socks_read_cb, NULL, error_cb, conn);
+ bufferevent_enable(conn->buffer, EV_READ|EV_WRITE);
+
+ /* Do not create a circuit at this time; the socks handler will do
+ it after it learns the remote peer address. */
log_debug("%s: setup complete", conn->peername);
}
@@ -318,25 +309,16 @@ socks_client_listener_cb(conn_t *conn, struct bufferevent *buf)
server mode.
*/
static void
-simple_server_listener_cb(conn_t *conn, struct bufferevent *buf)
+simple_server_listener_cb(conn_t *conn)
{
- struct event_base *base = bufferevent_get_base(buf);
- obfs_assert(buf);
obfs_assert(conn);
obfs_assert(conn->mode == LSN_SIMPLE_SERVER);
log_debug("%s: server connection", conn->peername);
- conn->downstream = buf;
- bufferevent_setcb(conn->downstream,
- downstream_read_cb, NULL, error_cb, conn);
-
- /* Don't enable the downstream side for reading at this point; wait
- till the upstream side is established. */
+ bufferevent_setcb(conn->buffer, downstream_read_cb, NULL, error_cb, conn);
- /* New bufferevent to connect to the target address. */
- conn->upstream = open_outbound_socket(conn, base, upstream_read_cb);
- if (!conn->upstream) {
- close_conn(conn);
+ if (circuit_create(open_outbound(conn, upstream_read_cb), conn)) {
+ conn_free(conn);
return;
}
@@ -349,36 +331,29 @@ simple_server_listener_cb(conn_t *conn, struct bufferevent *buf)
static void
conn_free(conn_t *conn)
{
- if (conn->peername)
- free(conn->peername);
- if (conn->socks_state)
- socks_state_free(conn->socks_state);
- if (conn->upstream)
- bufferevent_free(conn->upstream);
- if (conn->downstream)
- bufferevent_free(conn->downstream);
-
- proto_conn_free(conn);
-}
-
-/**
- Closes a fully open connection.
-*/
-static void
-close_conn(conn_t *conn)
-{
- obfs_assert(connections);
- log_debug("Closing connection from %s; %d remaining",
- conn->peername, smartlist_len(connections) - 1);
-
- smartlist_remove(connections, conn);
- conn_free(conn);
-
- /* If this was the last connection AND we are shutting down,
- finish shutdown. */
- if (smartlist_len(connections) == 0 && shutting_down) {
- smartlist_free(connections);
- finish_shutdown();
+ if (conn->circuit)
+ circuit_free(conn->circuit); /* will recurse and take care of us */
+ else {
+ if (connections) {
+ smartlist_remove(connections, conn);
+ log_debug("Closing connection with %s; %d remaining",
+ conn->peername, smartlist_len(connections));
+ }
+ if (conn->peername)
+ free(conn->peername);
+ if (conn->socks_state)
+ socks_state_free(conn->socks_state);
+ if (conn->buffer)
+ bufferevent_free(conn->buffer);
+ proto_conn_free(conn);
+
+ /* If this was the last connection AND we are shutting down,
+ finish shutdown. */
+ if (shutting_down && (!connections || smartlist_len(connections) == 0)) {
+ if (connections)
+ smartlist_free(connections);
+ finish_shutdown();
+ }
}
}
@@ -387,25 +362,51 @@ close_conn(conn_t *conn)
empty.
*/
static void
-close_conn_on_flush(struct bufferevent *bev, void *arg)
+conn_free_on_flush(struct bufferevent *bev, void *arg)
{
conn_t *conn = arg;
log_debug("%s for %s", __func__, conn->peername);
if (evbuffer_get_length(bufferevent_get_output(bev)) == 0)
- close_conn(conn);
+ conn_free(conn);
+}
+
+static int
+circuit_create(conn_t *up, conn_t *down)
+{
+ if (!up || !down)
+ return -1;
+
+ circuit_t *r = xzalloc(sizeof(circuit_t));
+ r->upstream = up;
+ r->downstream = down;
+ up->circuit = r;
+ down->circuit = r;
+ return 0;
+}
+
+static void
+circuit_free(circuit_t *circuit)
+{
+ /* break the circular references before deallocating each side */
+ circuit->upstream->circuit = NULL;
+ circuit->downstream->circuit = NULL;
+ conn_free(circuit->upstream);
+ conn_free(circuit->downstream);
+ free(circuit);
}
/**
- Make the outbound socket for a connection.
+ Make the outbound connection for a circuit.
*/
-static struct bufferevent *
-open_outbound_socket(conn_t *conn, struct event_base *base,
- bufferevent_data_cb readcb)
+static conn_t *
+open_outbound(conn_t *conn, bufferevent_data_cb readcb)
{
struct evutil_addrinfo *addr = config_get_target_addr(conn->cfg);
+ struct event_base *base = bufferevent_get_base(conn->buffer);
struct bufferevent *buf;
char *peername;
+ conn_t *newconn;
if (!addr) {
log_warn("%s: no target addresses available", conn->peername);
@@ -418,18 +419,23 @@ open_outbound_socket(conn_t *conn, struct event_base *base,
return NULL;
}
- bufferevent_setcb(buf, readcb, NULL, pending_conn_cb, conn);
+ newconn = proto_conn_create(conn->cfg);
+ if (!conn) {
+ log_warn("%s: failed to allocate state for outbound connection",
+ conn->peername);
+ bufferevent_free(buf);
+ return NULL;
+ }
+
+ newconn->buffer = buf;
+ bufferevent_setcb(buf, readcb, NULL, pending_conn_cb, newconn);
do {
peername = printable_address(addr->ai_addr, addr->ai_addrlen);
log_info("%s (%s): trying to connect to %s",
conn->peername, conn->cfg->vtable->name, peername);
- if (bufferevent_socket_connect(buf, addr->ai_addr, addr->ai_addrlen) >= 0) {
- /* success */
- bufferevent_enable(buf, EV_READ|EV_WRITE);
- free(peername);
- return buf;
- }
+ if (bufferevent_socket_connect(buf, addr->ai_addr, addr->ai_addrlen) >= 0)
+ goto success;
log_info("%s: connection to %s failed: %s",
conn->peername, peername,
evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()));
@@ -440,8 +446,55 @@ open_outbound_socket(conn_t *conn, struct event_base *base,
log_warn("%s: all outbound connection attempts failed",
conn->peername);
- bufferevent_free(buf);
+ conn_free(newconn);
return NULL;
+
+ success:
+ bufferevent_enable(buf, EV_READ|EV_WRITE);
+ newconn->peername = peername;
+ obfs_assert(connections);
+ smartlist_add(connections, newconn);
+ return newconn;
+}
+
+/**
+ As open_outbound, but uses bufferevent_socket_connect_hostname
+ rather than bufferevent_socket_connect.
+*/
+static conn_t *
+open_outbound_hostname(conn_t *conn, int af, const char *addr, int port)
+{
+ struct event_base *base = bufferevent_get_base(conn->buffer);
+ struct bufferevent *buf;
+ conn_t *newconn;
+
+ buf = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
+ if (!buf) {
+ log_warn("%s: unable to create outbound socket buffer", conn->peername);
+ return NULL;
+ }
+ newconn = proto_conn_create(conn->cfg);
+ if (!conn) {
+ log_warn("%s: failed to allocate state for outbound connection",
+ conn->peername);
+ bufferevent_free(buf);
+ return NULL;
+ }
+ newconn->buffer = buf;
+ bufferevent_setcb(buf, downstream_read_cb, NULL, pending_socks_cb, newconn);
+ if (bufferevent_socket_connect_hostname(buf, get_evdns_base(),
+ af, addr, port) < 0) {
+ log_warn("%s: outbound connection to %s:%d failed: %s",
+ conn->peername, addr, port,
+ evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()));
+ conn_free(newconn);
+ return NULL;
+ }
+
+ bufferevent_enable(buf, EV_READ|EV_WRITE);
+ obfs_assert(connections);
+ smartlist_add(connections, newconn);
+ return newconn;
}
/**
@@ -452,9 +505,7 @@ socks_read_cb(struct bufferevent *bev, void *arg)
{
conn_t *conn = arg;
enum socks_ret socks_ret;
- log_debug("%s for %s", __func__, conn->peername);
- /* socks only makes sense on the upstream side */
- obfs_assert(bev == conn->upstream);
+ log_debug("%s: %s", conn->peername, __func__);
do {
enum socks_status_t status = socks_state_get_status(conn->socks_state);
@@ -466,27 +517,16 @@ 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->downstream =
- bufferevent_socket_new(bufferevent_get_base(conn->upstream),
- -1, BEV_OPT_CLOSE_ON_FREE);
-
- bufferevent_setcb(conn->downstream,
- downstream_read_cb, NULL, pending_socks_cb, conn);
-
- r = bufferevent_socket_connect_hostname(conn->downstream,
- get_evdns_base(),
- af, addr, port);
- bufferevent_enable(conn->downstream, EV_READ|EV_WRITE);
- log_debug("socket_connect_hostname said %d! (%s,%d)", r, addr, port);
-
- if (r < 0) {
+ log_info("%s: socks: trying to connect to %s:%u",
+ conn->peername, addr, port);
+ if (circuit_create(conn, open_outbound_hostname(conn, af, addr, port))) {
/* XXXX send socks reply */
- close_conn(conn);
+ conn_free(conn);
return;
}
/* further upstream data will be processed once the downstream
side is established */
- bufferevent_disable(conn->upstream, EV_READ|EV_WRITE);
+ bufferevent_disable(conn->buffer, EV_READ|EV_WRITE);
return;
}
@@ -498,14 +538,14 @@ socks_read_cb(struct bufferevent *bev, void *arg)
if (socks_ret == SOCKS_INCOMPLETE)
return; /* need to read more data. */
else if (socks_ret == SOCKS_BROKEN)
- close_conn(conn); /* XXXX send socks reply */
+ conn_free(conn); /* XXXX send socks reply */
else if (socks_ret == SOCKS_CMD_NOT_CONNECT) {
bufferevent_enable(bev, EV_WRITE);
bufferevent_disable(bev, EV_READ);
socks5_send_reply(bufferevent_get_output(bev), conn->socks_state,
SOCKS5_FAILED_UNSUPPORTED);
bufferevent_setcb(bev, NULL,
- close_conn_on_flush, flush_error_cb, conn);
+ conn_free_on_flush, flush_error_cb, conn);
return;
}
}
@@ -518,17 +558,27 @@ socks_read_cb(struct bufferevent *bev, void *arg)
static void
upstream_read_cb(struct bufferevent *bev, void *arg)
{
- conn_t *conn = arg;
- log_debug("%s: %s, %lu bytes available", conn->peername, __func__,
+ conn_t *up = arg;
+ conn_t *down;
+ log_debug("%s: %s, %lu bytes available", up->peername, __func__,
(unsigned long)evbuffer_get_length(bufferevent_get_input(bev)));
- obfs_assert(bev == conn->upstream);
- if (proto_send(conn,
- bufferevent_get_input(conn->upstream),
- bufferevent_get_output(conn->downstream)) < 0) {
- log_debug("%s: Error during transmit.", conn->peername);
- close_conn(conn);
+ obfs_assert(up->buffer == bev);
+ obfs_assert(!up->flushing);
+ obfs_assert(up->is_open);
+ obfs_assert(up->circuit);
+ obfs_assert(up->circuit->downstream);
+
+ down = up->circuit->downstream;
+ if (proto_send(up,
+ bufferevent_get_input(up->buffer),
+ bufferevent_get_output(down->buffer))) {
+ log_debug("%s: error during transmit.", up->peername);
+ conn_free(up);
}
+ log_debug("%s: transmitted %lu bytes", down->peername,
+ (unsigned long)
+ evbuffer_get_length(bufferevent_get_output(down->buffer)));
}
/**
@@ -539,28 +589,45 @@ upstream_read_cb(struct bufferevent *bev, void *arg)
static void
downstream_read_cb(struct bufferevent *bev, void *arg)
{
- conn_t *conn = arg;
+ conn_t *down = arg;
+ conn_t *up;
enum recv_ret r;
- log_debug("%s: %s, %lu bytes available", conn->peername, __func__,
+
+ log_debug("%s: %s, %lu bytes available", down->peername, __func__,
(unsigned long)evbuffer_get_length(bufferevent_get_input(bev)));
- obfs_assert(bev == conn->downstream);
- r = proto_recv(conn,
- bufferevent_get_input(conn->downstream),
- bufferevent_get_output(conn->upstream));
+ obfs_assert(down->buffer == bev);
+ obfs_assert(!down->flushing);
+ obfs_assert(down->is_open);
+ obfs_assert(down->circuit);
+ obfs_assert(down->circuit->upstream);
+ up = down->circuit->upstream;
+
+
+ r = proto_recv(down,
+ bufferevent_get_input(down->buffer),
+ bufferevent_get_output(up->buffer));
if (r == RECV_BAD) {
- log_debug("%s: Error during receive.", conn->peername);
- close_conn(conn);
- } else if (r == RECV_SEND_PENDING) {
- log_debug("%s: Reply of %lu bytes", conn->peername,
+ log_debug("%s: error during receive.", down->peername);
+ conn_free(down);
+ } else {
+ log_debug("%s: forwarded %lu bytes", down->peername,
(unsigned long)
- evbuffer_get_length(bufferevent_get_input(conn->upstream)));
- if (proto_send(conn,
- bufferevent_get_input(conn->upstream),
- bufferevent_get_output(conn->downstream)) < 0) {
- log_debug("%s: Error during reply.", conn->peername);
- close_conn(conn);
+ evbuffer_get_length(bufferevent_get_output(up->buffer)));
+ if (r == RECV_SEND_PENDING) {
+ log_debug("%s: reply of %lu bytes", down->peername,
+ (unsigned long)
+ evbuffer_get_length(bufferevent_get_input(up->buffer)));
+ if (proto_send(up,
+ bufferevent_get_input(up->buffer),
+ bufferevent_get_output(down->buffer)) < 0) {
+ log_debug("%s: error during reply.", down->peername);
+ conn_free(down);
+ }
+ log_debug("%s: transmitted %lu bytes", down->peername,
+ (unsigned long)
+ evbuffer_get_length(bufferevent_get_output(down->buffer)));
}
}
}
@@ -570,22 +637,29 @@ downstream_read_cb(struct bufferevent *bev, void *arg)
We prepare the connection to be closed ASAP.
*/
static void
-error_or_eof(conn_t *conn, struct bufferevent *bev_err)
+error_or_eof(conn_t *conn)
{
+ circuit_t *circ = conn->circuit;
+ struct bufferevent *bev_err = conn->buffer;
struct bufferevent *bev_flush;
- log_debug("%s for %s", __func__, conn->peername);
- if (bev_err == conn->upstream) bev_flush = conn->downstream;
- else if (bev_err == conn->downstream) bev_flush = conn->upstream;
- else obfs_abort();
+ log_debug("%s for %s", __func__, conn->peername);
+ if (!circ || conn->flushing || !conn->is_open) {
+ conn_free(conn);
+ return;
+ }
- if (conn->flushing || !conn->is_open ||
- evbuffer_get_length(bufferevent_get_output(bev_flush)) == 0) {
- close_conn(conn);
+ bev_flush = (conn == circ->upstream) ? circ->downstream->buffer
+ : circ->upstream->buffer;
+ if (evbuffer_get_length(bufferevent_get_output(bev_flush)) == 0) {
+ conn_free(conn);
return;
}
- conn->flushing = 1;
+ /* XXX move ->flushing and ->is_open to circuit_t */
+ circ->upstream->flushing = 1;
+ circ->downstream->flushing = 1;
+
/* Stop reading and writing; wait for the other side to flush if it has
* data. */
bufferevent_disable(bev_err, EV_READ|EV_WRITE);
@@ -595,7 +669,7 @@ error_or_eof(conn_t *conn, struct bufferevent *bev_err)
official API to retrieve the callback functions and/or change
just one callback while leaving the others intact. */
bufferevent_setcb(bev_flush, bev_flush->readcb,
- close_conn_on_flush, flush_error_cb, conn);
+ conn_free_on_flush, flush_error_cb, conn);
}
/**
@@ -607,7 +681,7 @@ error_cb(struct bufferevent *bev, short what, void *arg)
{
conn_t *conn = arg;
int errcode = EVUTIL_SOCKET_ERROR();
- log_debug("%s for %s: what=%x err=%d", __func__, conn->peername,
+ log_debug("%s for %s: what=0x%04x errno=%d", __func__, conn->peername,
what, errcode);
/* It should be impossible to get here with BEV_EVENT_CONNECTED. */
@@ -615,21 +689,16 @@ error_cb(struct bufferevent *bev, short what, void *arg)
obfs_assert(!(what & BEV_EVENT_CONNECTED));
if (what & BEV_EVENT_ERROR) {
- log_warn("Error on %s side of connection from %s: %s",
- bev == conn->upstream ? "upstream" : "downstream",
+ log_warn("Error talking to %s: %s",
conn->peername,
evutil_socket_error_to_string(errcode));
} else if (what & BEV_EVENT_EOF) {
- log_info("EOF on %s side of connection from %s",
- bev == conn->upstream ? "upstream" : "downstream",
- conn->peername);
+ log_info("EOF from %s", conn->peername);
} else {
obfs_assert(what & BEV_EVENT_TIMEOUT);
- log_info("Timeout on %s side of connection from %s",
- bev == conn->upstream ? "upstream" : "downstream",
- conn->peername);
+ log_info("Timeout talking to %s", conn->peername);
}
- error_or_eof(arg, bev);
+ error_or_eof(conn);
}
/**
@@ -641,7 +710,7 @@ flush_error_cb(struct bufferevent *bev, short what, void *arg)
{
conn_t *conn = arg;
int errcode = EVUTIL_SOCKET_ERROR();
- log_debug("%s for %s: what=%x err=%d", __func__, conn->peername,
+ log_debug("%s for %s: what=0x%04x errno=%d", __func__, conn->peername,
what, errcode);
/* It should be impossible to get here with BEV_EVENT_CONNECTED. */
@@ -650,11 +719,10 @@ flush_error_cb(struct bufferevent *bev, short what, void *arg)
obfs_assert(conn->flushing);
- log_warn("Error during flush of %s side of connection from %s: %s",
- bev == conn->upstream ? "upstream" : "downstream",
+ log_warn("Error during flush of connection with %s: %s",
conn->peername,
evutil_socket_error_to_string(errcode));
- close_conn(conn);
+ conn_free(conn);
return;
}
@@ -668,35 +736,36 @@ static void
pending_conn_cb(struct bufferevent *bev, short what, void *arg)
{
conn_t *conn = arg;
- struct bufferevent *other;
log_debug("%s: %s", conn->peername, __func__);
- if (bev == conn->upstream) other = conn->downstream;
- else if (bev == conn->downstream) other = conn->upstream;
- else obfs_abort();
-
- /* Upon successful connection, enable traffic on the other side,
- and replace this callback with the regular error_cb */
+ /* Upon successful connection, enable traffic on both sides of the
+ connection, and replace this callback with the regular error_cb */
if (what & BEV_EVENT_CONNECTED) {
- obfs_assert(!conn->flushing);
+ circuit_t *circ = conn->circuit;
+ obfs_assert(circ);
+ obfs_assert(!circ->upstream->flushing);
+ obfs_assert(!circ->downstream->flushing);
+
+ circ->upstream->is_open = 1;
+ circ->downstream->is_open = 1;
- conn->is_open = 1;
- log_debug("%s: Successful %s connection", conn->peername,
- bev == conn->upstream ? "upstream" : "downstream");
+ log_debug("%s: Successful connection", conn->peername);
/* Queue handshake, if any. */
- if (proto_handshake(conn,
- bufferevent_get_output(conn->downstream))<0) {
+ if (proto_handshake(circ->downstream,
+ bufferevent_get_output(circ->downstream->buffer))<0) {
log_debug("%s: Error during handshake", conn->peername);
- close_conn(conn);
+ conn_free(conn);
return;
}
- /* XXX Dirty access to bufferevent guts. There appears to be no
- official API to retrieve the callback functions and/or change
- just one callback while leaving the others intact. */
- bufferevent_setcb(bev, bev->readcb, bev->writecb, error_cb, conn);
- bufferevent_enable(other, EV_READ|EV_WRITE);
+ bufferevent_setcb(circ->upstream->buffer,
+ upstream_read_cb, NULL, error_cb, circ->upstream);
+ bufferevent_setcb(circ->downstream->buffer,
+ downstream_read_cb, NULL, error_cb, circ->downstream);
+
+ bufferevent_enable(circ->upstream->buffer, EV_READ|EV_WRITE);
+ bufferevent_enable(circ->downstream->buffer, EV_READ|EV_WRITE);
return;
}
@@ -712,10 +781,20 @@ pending_conn_cb(struct bufferevent *bev, short what, void *arg)
static void
pending_socks_cb(struct bufferevent *bev, short what, void *arg)
{
- conn_t *conn = arg;
- log_debug("%s: %s", conn->peername, __func__);
- obfs_assert(bev == conn->downstream);
- obfs_assert(conn->socks_state);
+ conn_t *down = arg;
+ circuit_t *circ = down->circuit;
+ conn_t *up;
+ socks_state_t *socks;
+
+ log_debug("%s: %s", down->peername, __func__);
+
+ obfs_assert(circ);
+ obfs_assert(circ->upstream);
+ obfs_assert(circ->upstream->socks_state);
+ obfs_assert(circ->downstream == down);
+
+ up = circ->upstream;
+ socks = circ->upstream->socks_state;
/* If we got an error while in the ST_HAVE_ADDR state, chances are
that we failed connecting to the host requested by the CONNECT
@@ -725,14 +804,11 @@ pending_socks_cb(struct bufferevent *bev, short what, void *arg)
errno isn't meaningful in that case... */
if ((what & (BEV_EVENT_EOF|BEV_EVENT_ERROR|BEV_EVENT_TIMEOUT))) {
int err = EVUTIL_SOCKET_ERROR();
- log_warn("Connection error: %s",
- evutil_socket_error_to_string(err));
- if (socks_state_get_status(conn->socks_state) == ST_HAVE_ADDR) {
- socks_send_reply(conn->socks_state,
- bufferevent_get_output(conn->upstream),
- err);
+ log_warn("Connection error: %s", evutil_socket_error_to_string(err));
+ if (socks_state_get_status(socks) == ST_HAVE_ADDR) {
+ socks_send_reply(socks, bufferevent_get_output(up->buffer), err);
}
- error_or_eof(conn, bev);
+ error_or_eof(down);
return;
}
@@ -744,39 +820,39 @@ pending_socks_cb(struct bufferevent *bev, short what, void *arg)
struct sockaddr *sa = (struct sockaddr*)&ss;
socklen_t slen = sizeof(&ss);
- obfs_assert(!conn->flushing);
+ obfs_assert(!up->flushing);
+ obfs_assert(!down->flushing);
+ /* Figure out where we actually connected to, and tell the socks client */
if (getpeername(bufferevent_getfd(bev), sa, &slen) == 0) {
- /* Figure out where we actually connected to so that we can tell the
- * socks client */
- socks_state_set_address(conn->socks_state, sa);
+ socks_state_set_address(socks, sa);
+ if (!down->peername)
+ down->peername = printable_address(sa, slen);
}
- socks_send_reply(conn->socks_state,
- bufferevent_get_output(conn->upstream), 0);
+ socks_send_reply(socks, bufferevent_get_output(up->buffer), 0);
/* Switch to regular upstream behavior. */
- socks_state_free(conn->socks_state);
- conn->socks_state = NULL;
- conn->is_open = 1;
- log_debug("%s: Successful %s connection", conn->peername,
- bev == conn->upstream ? "upstream" : "downstream");
-
- bufferevent_setcb(conn->upstream,
- upstream_read_cb, NULL, error_cb, conn);
- bufferevent_setcb(conn->downstream,
- downstream_read_cb, NULL, error_cb, conn);
- bufferevent_enable(conn->upstream, EV_READ|EV_WRITE);
+ socks_state_free(socks);
+ up->socks_state = NULL;
+ up->is_open = 1;
+ down->is_open = 1;
+ log_debug("%s: Successful outbound connection to %s",
+ up->peername, down->peername);
+
+ bufferevent_setcb(up->buffer, upstream_read_cb, NULL, error_cb, up);
+ bufferevent_setcb(down->buffer, downstream_read_cb, NULL, error_cb, down);
+ bufferevent_enable(up->buffer, EV_READ|EV_WRITE);
+ bufferevent_enable(down->buffer, EV_READ|EV_WRITE);
/* Queue handshake, if any. */
- if (proto_handshake(conn,
- bufferevent_get_output(conn->downstream))<0) {
- log_debug("%s: Error during handshake", conn->peername);
- close_conn(conn);
+ if (proto_handshake(down, bufferevent_get_output(down->buffer))) {
+ log_debug("%s: Error during handshake", down->peername);
+ conn_free(down);
return;
}
- if (evbuffer_get_length(bufferevent_get_input(conn->upstream)) != 0)
- upstream_read_cb(conn->upstream, conn);
+ if (evbuffer_get_length(bufferevent_get_input(up->buffer)) > 0)
+ upstream_read_cb(up->buffer, up);
return;
}
diff --git a/src/network.h b/src/network.h
index 8fb41ef..72df32c 100644
--- a/src/network.h
+++ b/src/network.h
@@ -12,23 +12,37 @@ void close_all_listeners(void);
void start_shutdown(int barbaric);
/**
- This struct defines the state of a connection between "upstream"
- and "downstream" peers (it's really two connections at the socket
- level). Again, each protocol may extend this structure with
- additional private data by embedding it as the first member of a
- larger structure. The protocol's conn_create() method is responsible
- only for filling in the |vtable| field of this structure, plus any
- private data of course.
+ This struct defines the state of one socket-level connection. Each
+ protocol may extend this structure with additional private data by
+ embedding it as the first member of a larger structure. The
+ protocol's conn_create() method is responsible only for filling in
+ the |cfg| and |mode| fields of this structure, plus any private
+ data of course.
+
+ An incoming connection is not associated with a circuit until the
+ destination for the other side of the circuit is known. An outgoing
+ connection is associated with a circuit from its creation.
*/
struct conn_t {
config_t *cfg;
char *peername;
socks_state_t *socks_state;
- struct bufferevent *upstream;
- struct bufferevent *downstream;
+ circuit_t *circuit;
+ struct bufferevent *buffer;
enum listen_mode mode : 30;
unsigned int flushing : 1;
unsigned int is_open : 1;
};
+/**
+ This struct defines a pair of established connections. The "upstream"
+ connection is to the higher-level client or server that we are proxying
+ traffic for. The "downstream" connection is to the remote peer.
+ */
+
+struct circuit_t {
+ conn_t *upstream;
+ conn_t *downstream;
+};
+
#endif
diff --git a/src/util.h b/src/util.h
index 8228790..2b37c48 100644
--- a/src/util.h
+++ b/src/util.h
@@ -62,6 +62,7 @@ unsigned int ui64_log2(uint64_t u64);
/***** Network types and functions. *****/
+typedef struct circuit_t circuit_t;
typedef struct config_t config_t;
typedef struct conn_t conn_t;
typedef struct protocol_vtable protocol_vtable;
1
0
[obfsproxy/master] Avoid double-freeing the connections smartlist on barbaric shutdown.
by nickm@torproject.org 09 Sep '11
by nickm@torproject.org 09 Sep '11
09 Sep '11
commit 9c4f2a0a82964b6137c9286cee5122ca493ed5de
Author: George Kadianakis <desnacked(a)gmail.com>
Date: Fri Aug 19 18:14:09 2011 +0200
Avoid double-freeing the connections smartlist on barbaric shutdown.
---
src/network.c | 36 ++++++++++--------------------------
1 files changed, 10 insertions(+), 26 deletions(-)
diff --git a/src/network.c b/src/network.c
index cc5b633..62a45b8 100644
--- a/src/network.c
+++ b/src/network.c
@@ -79,7 +79,6 @@ static void socks_client_listener_cb(conn_t *conn);
static void simple_server_listener_cb(conn_t *conn);
static void conn_free(conn_t *conn);
-static void conn_free_all(void);
static void conn_free_on_flush(struct bufferevent *bev, void *arg);
static int circuit_create(conn_t *up, conn_t *down);
@@ -115,31 +114,16 @@ start_shutdown(int barbaric)
if (!shutting_down)
shutting_down=1;
- if (barbaric)
- conn_free_all();
-
- if (connections && smartlist_len(connections) == 0) {
+ if (!connections) {
+ finish_shutdown();
+ } else if (smartlist_len(connections) == 0) {
smartlist_free(connections);
connections = NULL;
- }
-
- if (!connections)
finish_shutdown();
-}
-
-/**
- Closes all open connections.
-*/
-static void
-conn_free_all(void)
-{
- if (!connections)
- return;
- log_debug("Closing all connections.");
- SMARTLIST_FOREACH(connections, conn_t *, conn,
- { conn_free(conn); });
- smartlist_free(connections);
- connections = NULL;
+ } else if (barbaric) {
+ while (connections) /* last conn_free() will free connections smartlist */
+ conn_free(smartlist_get(connections,0));
+ }
}
/**
@@ -349,9 +333,9 @@ conn_free(conn_t *conn)
/* If this was the last connection AND we are shutting down,
finish shutdown. */
- if (shutting_down && (!connections || smartlist_len(connections) == 0)) {
- if (connections)
- smartlist_free(connections);
+ if (shutting_down && connections && smartlist_len(connections) == 0) {
+ smartlist_free(connections);
+ connections = NULL;
finish_shutdown();
}
}
1
0
09 Sep '11
commit c85e65fad3d787f4e3d1643f27a01400afceb0a4
Author: George Kadianakis <desnacked(a)gmail.com>
Date: Sat Aug 20 03:26:12 2011 +0200
Ancient spirits of evil, revive obfs2.
---
Makefile.am | 11 ++--
src/protocol.c | 4 +-
src/protocols/obfs2.c | 191 ++++++++++++++++++++++++++++++------------------
src/protocols/obfs2.h | 25 ++++---
4 files changed, 142 insertions(+), 89 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index ece6069..eb35e15 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -16,7 +16,8 @@ libobfsproxy_a_SOURCES = \
src/protocol.c \
src/socks.c \
src/util.c \
- src/protocols/dummy.c
+ src/protocols/dummy.c \
+ src/protocols/obfs2.c
if NEED_SHA256
libobfsproxy_a_SOURCES += src/sha256.c
endif
@@ -30,7 +31,8 @@ unittests_SOURCES = \
src/test/unittest_container.c \
src/test/unittest_crypt.c \
src/test/unittest_socks.c \
- src/test/unittest_dummy.c
+ src/test/unittest_dummy.c \
+ src/test/unittest_obfs2.c
noinst_HEADERS = \
src/container.h \
@@ -47,10 +49,7 @@ noinst_HEADERS = \
src/test/tinytest.h \
src/test/tinytest_macros.h
-EXTRA_DIST = doc/protocol-spec.txt \
- src/protocols/obfs2.c \
- src/test/unittest_obfs2.c
-
+EXTRA_DIST = doc/protocol-spec.txt
TESTS = unittests
diff --git a/src/protocol.c b/src/protocol.c
index e5d1818..65eacf8 100644
--- a/src/protocol.c
+++ b/src/protocol.c
@@ -7,7 +7,7 @@
#include "protocol.h"
#include "protocols/dummy.h"
-/*#include "protocols/obfs2.h"*/
+#include "protocols/obfs2.h"
/**
All supported protocols should be put in this array.
@@ -16,7 +16,7 @@
const protocol_vtable *const supported_protocols[] =
{
&dummy_vtable,
- /*&obfs2_vtable,*/
+ &obfs2_vtable
};
const size_t n_supported_protocols =
sizeof(supported_protocols)/sizeof(supported_protocols[0]);
diff --git a/src/protocols/obfs2.c b/src/protocols/obfs2.c
index 94fd173..366bc45 100644
--- a/src/protocols/obfs2.c
+++ b/src/protocols/obfs2.c
@@ -10,21 +10,23 @@
#include <event2/buffer.h>
/* type-safe downcast wrappers */
-static inline obfs2_params_t *
-downcast_params(protocol_params_t *p)
+static inline obfs2_config_t *
+downcast_config(config_t *p)
{
- return DOWNCAST(obfs2_params_t, super, p);
+ return DOWNCAST(obfs2_config_t, super, p);
}
-static inline obfs2_protocol_t *
-downcast_protocol(protocol_t *p)
+static inline obfs2_conn_t *
+downcast_conn(conn_t *p)
{
- return DOWNCAST(obfs2_protocol_t, super, p);
+ return DOWNCAST(obfs2_conn_t, super, p);
}
static int parse_and_set_options(int n_options,
const char *const *options,
- obfs2_params_t *params);
+ obfs2_config_t *params);
+static obfs2_state_t *state_create(config_t *p);
+static void obfs2_destroy(obfs2_state_t *state);
/** Return true iff the OBFUSCATE_SEED_LENGTH-byte seed in 'seed' is nonzero */
static inline int
@@ -42,22 +44,45 @@ shared_seed_nonzero(const uchar *seed)
return memcmp(seed, SHARED_ZERO_SEED, SHARED_SECRET_LENGTH) != 0;
}
+/** stupid function returning the other conn of the circuit */
+static inline conn_t *
+get_other_conn(conn_t *conn)
+{
+ if (conn->circuit->upstream == conn) {
+ return conn->circuit->downstream;
+ } else {
+ obfs_assert(conn->circuit->downstream == conn);
+ return conn->circuit->upstream;
+ }
+}
+
+static void
+obfs2_config_free(config_t *c)
+{
+ obfs2_config_t *cfg = downcast_config(c);
+ if (cfg->listen_addr)
+ evutil_freeaddrinfo(cfg->listen_addr);
+ if (cfg->target_addr)
+ evutil_freeaddrinfo(cfg->target_addr);
+ free(cfg);
+}
+
/*
This function parses 'options' and fills the protocol parameters
structure 'params'.
Returns 0 on success, -1 on fail.
*/
-static protocol_params_t *
-obfs2_init(int n_options, const char *const *options)
+static config_t *
+obfs2_config_create(int n_options, const char *const *options)
{
- obfs2_params_t *params = xzalloc(sizeof(obfs2_params_t));
- params->super.vtable = &obfs2_vtable;
+ obfs2_config_t *cfg = xzalloc(sizeof(obfs2_config_t));
+ cfg->super.vtable = &obfs2_vtable;
- if (parse_and_set_options(n_options, options, params) == 0)
- return ¶ms->super;
+ if (parse_and_set_options(n_options, options, cfg) == 0)
+ return &cfg->super;
- proto_params_free(¶ms->super);
+ obfs2_config_free(&cfg->super);
log_warn("You failed at creating a correct obfs2 line.\n"
"obfs2 syntax:\n"
"\tobfs2 [obfs2_args] obfs2_opts\n"
@@ -74,11 +99,11 @@ obfs2_init(int n_options, const char *const *options)
}
/**
- Helper: Parses 'options' and fills 'params'.
+ Helper: Parses 'options' and fills 'cfg'.
*/
int
parse_and_set_options(int n_options, const char *const *options,
- obfs2_params_t *params)
+ obfs2_config_t *cfg)
{
int got_dest=0;
int got_ss=0;
@@ -94,9 +119,9 @@ parse_and_set_options(int n_options, const char *const *options,
if (!strncmp(*options,"--dest=",7)) {
if (got_dest)
return -1;
- params->super.target_addr =
+ cfg->target_addr =
resolve_address_port(*options+7, 1, 0, NULL);
- if (!params->super.target_addr)
+ if (!cfg->target_addr)
return -1;
got_dest=1;
} else if (!strncmp(*options,"--shared-secret=",16)) {
@@ -104,11 +129,9 @@ parse_and_set_options(int n_options, const char *const *options,
if (got_ss)
return -1;
- /* ASN we must say in spec that we hash command line shared
- secret. */
c = digest_new();
digest_update(c, (uchar*)*options+16, strlen(*options+16));
- digest_getdigest(c, params->shared_secret, SHARED_SECRET_LENGTH);
+ digest_getdigest(c, cfg->shared_secret, SHARED_SECRET_LENGTH);
digest_free(c);
got_ss=1;
@@ -121,30 +144,30 @@ parse_and_set_options(int n_options, const char *const *options,
if (!strcmp(*options, "client")) {
defport = "48988"; /* bf5c */
- params->super.mode = LSN_SIMPLE_CLIENT;
+ cfg->mode = LSN_SIMPLE_CLIENT;
} else if (!strcmp(*options, "socks")) {
defport = "23548"; /* 5bf5 */
- params->super.mode = LSN_SOCKS_CLIENT;
+ cfg->mode = LSN_SOCKS_CLIENT;
} else if (!strcmp(*options, "server")) {
defport = "11253"; /* 2bf5 */
- params->super.mode = LSN_SIMPLE_SERVER;
+ cfg->mode = LSN_SIMPLE_SERVER;
} else {
log_warn("obfs2: only client/socks/server modes supported.");
return -1;
}
options++;
- params->super.listen_addr = resolve_address_port(*options, 1, 1, defport);
- if (!params->super.listen_addr)
+ cfg->listen_addr = resolve_address_port(*options, 1, 1, defport);
+ if (!cfg->listen_addr)
return -1;
/* Validate option selection. */
- if (got_dest && (params->super.mode == LSN_SOCKS_CLIENT)) {
+ if (got_dest && (cfg->mode == LSN_SOCKS_CLIENT)) {
log_warn("obfs2: You can't be on socks mode and have --dest.");
return -1;
}
- if (!got_dest && (params->super.mode != LSN_SOCKS_CLIENT)) {
+ if (!got_dest && (cfg->mode != LSN_SOCKS_CLIENT)) {
log_warn("obfs2: client/server mode needs --dest.");
return -1;
}
@@ -154,14 +177,55 @@ parse_and_set_options(int n_options, const char *const *options,
return 0;
}
+
+/** Retrieve the 'n'th set of listen addresses for this configuration. */
+static struct evutil_addrinfo *
+obfs2_config_get_listen_addrs(config_t *cfg, size_t n)
+{
+ if (n > 0)
+ return 0;
+ return downcast_config(cfg)->listen_addr;
+}
+
+/* Retrieve the target address for this configuration. */
+static struct evutil_addrinfo *
+obfs2_config_get_target_addr(config_t *cfg)
+{
+ return downcast_config(cfg)->target_addr;
+}
+
+/*
+ This is called everytime we get a connection for the dummy
+ protocol.
+*/
+
+static conn_t *
+obfs2_conn_create(config_t *cfg)
+{
+ obfs2_conn_t *conn = xzalloc(sizeof(obfs2_conn_t));
+ conn->super.cfg = cfg;
+ conn->super.mode = downcast_config(cfg)->mode;
+ conn->state = state_create(cfg);
+
+ return &conn->super;
+}
+
+static void
+obfs2_conn_free(conn_t *conn)
+{
+ obfs2_conn_t *obfs2_conn = downcast_conn(conn);
+
+ obfs2_destroy(obfs2_conn->state);
+ free(obfs2_conn);
+}
+
/**
Derive and return key of type 'keytype' from the seeds currently set in
'state'.
*/
static crypt_t *
-derive_key(void *s, const char *keytype)
+derive_key(obfs2_state_t *state, const char *keytype)
{
- obfs2_protocol_t *state = s;
crypt_t *cryptstate;
uchar buf[SHA256_LENGTH];
digest_t *c = digest_new();
@@ -199,11 +263,9 @@ derive_key(void *s, const char *keytype)
currently set in state 's'.
*/
static crypt_t *
-derive_padding_key(void *s, const uchar *seed,
+derive_padding_key(obfs2_state_t *state, const uchar *seed,
const char *keytype)
{
- obfs2_protocol_t *state = s;
-
crypt_t *cryptstate;
uchar buf[SHA256_LENGTH];
digest_t *c = digest_new();
@@ -235,61 +297,48 @@ derive_padding_key(void *s, const uchar *seed,
}
/**
- Frees obfs2 parameters 'p'
- */
-static void
-obfs2_fini(protocol_params_t *p)
-{
- obfs2_params_t *params = downcast_params(p);
- /* wipe out keys */
- memset(params, 0x99, sizeof(obfs2_params_t));
- free(params);
-}
-
-
-/**
This is called everytime we get a connection for the obfs2
protocol.
*/
-static protocol_t *
-obfs2_create(protocol_params_t *p)
+static obfs2_state_t *
+state_create(config_t *p)
{
- obfs2_params_t *params = downcast_params(p);
- obfs2_protocol_t *proto = xzalloc(sizeof(obfs2_protocol_t));
+ obfs2_config_t *cfg = downcast_config(p);
+
+ obfs2_state_t *state = xzalloc(sizeof(obfs2_state_t));
uchar *seed;
const char *send_pad_type;
- proto->state = ST_WAIT_FOR_KEY;
- proto->we_are_initiator = (params->super.mode != LSN_SIMPLE_SERVER);
- if (proto->we_are_initiator) {
+ state->state = ST_WAIT_FOR_KEY;
+ state->we_are_initiator = (cfg->mode != LSN_SIMPLE_SERVER);
+ if (state->we_are_initiator) {
send_pad_type = INITIATOR_PAD_TYPE;
- seed = proto->initiator_seed;
+ seed = state->initiator_seed;
} else {
send_pad_type = RESPONDER_PAD_TYPE;
- seed = proto->responder_seed;
+ seed = state->responder_seed;
}
/* Generate our seed */
- memcpy(proto->secret_seed, params->shared_secret, SHARED_SECRET_LENGTH);
+ memcpy(state->secret_seed, cfg->shared_secret, SHARED_SECRET_LENGTH);
if (random_bytes(seed, OBFUSCATE_SEED_LENGTH) < 0) {
- free(proto);
+ free(state);
return NULL;
}
/* Derive the key for what we're sending */
- proto->send_padding_crypto = derive_padding_key(proto, seed, send_pad_type);
- proto->super.vtable = &obfs2_vtable;
- return &proto->super;
+ state->send_padding_crypto = derive_padding_key(state, seed, send_pad_type);
+
+ return state;
}
/**
Frees obfs2 state 's'
*/
static void
-obfs2_destroy(protocol_t *s)
+obfs2_destroy(obfs2_state_t *state)
{
- obfs2_protocol_t *state = downcast_protocol(s);
if (state->send_crypto)
crypt_free(state->send_crypto);
if (state->send_padding_crypto)
@@ -300,7 +349,7 @@ obfs2_destroy(protocol_t *s)
crypt_free(state->recv_padding_crypto);
if (state->pending_data_to_send)
evbuffer_free(state->pending_data_to_send);
- memset(state, 0x0a, sizeof(obfs2_protocol_t));
+ memset(state, 0x0a, sizeof(obfs2_state_t));
free(state);
}
@@ -310,9 +359,9 @@ obfs2_destroy(protocol_t *s)
the evbuffer 'buf'. Return 0 on success, -1 on failure.
*/
static int
-obfs2_handshake(protocol_t *s, struct evbuffer *buf)
+obfs2_handshake(conn_t *s, struct evbuffer *buf)
{
- obfs2_protocol_t *state = downcast_protocol(s);
+ obfs2_state_t *state = downcast_conn(s)->state;
uint32_t magic = htonl(OBFUSCATE_MAGIC_VALUE), plength, send_plength;
uchar msg[OBFUSCATE_MAX_PADDING + OBFUSCATE_SEED_LENGTH + 8];
@@ -381,10 +430,10 @@ obfs2_crypt_and_transmit(crypt_t *crypto,
using the state in 'state'. Returns 0 on success, -1 on failure.
*/
static int
-obfs2_send(protocol_t *s,
+obfs2_send(conn_t *s,
struct evbuffer *source, struct evbuffer *dest)
{
- obfs2_protocol_t *state = downcast_protocol(s);
+ obfs2_state_t *state = downcast_conn(get_other_conn(s))->state;
if (state->send_crypto) {
/* First of all, send any data that we've been waiting to send. */
@@ -423,10 +472,8 @@ obfs2_send(protocol_t *s,
keys. Returns 0 on success, -1 on failure.
*/
static void
-init_crypto(void *s)
+init_crypto(obfs2_state_t *state)
{
- obfs2_protocol_t *state = s;
-
const char *send_keytype;
const char *recv_keytype;
const char *recv_pad_keytype;
@@ -463,10 +510,10 @@ init_crypto(void *s)
* our callers that they must call obfs2_send() immediately.
*/
static enum recv_ret
-obfs2_recv(protocol_t *s, struct evbuffer *source,
+obfs2_recv(conn_t *s, struct evbuffer *source,
struct evbuffer *dest)
{
- obfs2_protocol_t *state = downcast_protocol(s);
+ obfs2_state_t *state = downcast_conn(s)->state;
if (state->state == ST_WAIT_FOR_KEY) {
/* We're waiting for the first OBFUSCATE_SEED_LENGTH+8 bytes to show up
diff --git a/src/protocols/obfs2.h b/src/protocols/obfs2.h
index e994d97..a8fe2cc 100644
--- a/src/protocols/obfs2.h
+++ b/src/protocols/obfs2.h
@@ -11,6 +11,7 @@ extern const protocol_vtable obfs2_vtable;
#include "crypt.h"
#include "protocol.h"
+#include "network.h"
/* ==========
These definitions are not part of the obfs2_protocol interface.
@@ -33,14 +34,7 @@ extern const protocol_vtable obfs2_vtable;
#define SHARED_SECRET_LENGTH SHA256_LENGTH
-typedef struct obfs2_params_t {
- protocol_params_t super;
- uchar shared_secret[SHARED_SECRET_LENGTH];
-} obfs2_params_t;
-
-typedef struct obfs2_protocol_t {
- protocol_t super;
-
+typedef struct obfs2_state_t {
/** Current protocol state. We start out waiting for key information. Then
we have a key and wait for padding to arrive. Finally, we are sending
and receiving bytes on the connection.
@@ -73,7 +67,20 @@ typedef struct obfs2_protocol_t {
/** Number of padding bytes to read before we get to real data */
int padding_left_to_read;
-} obfs2_protocol_t;
+} obfs2_state_t;
+
+typedef struct obfs2_config_t {
+ config_t super;
+ struct evutil_addrinfo *listen_addr;
+ struct evutil_addrinfo *target_addr;
+ enum listen_mode mode;
+ uchar shared_secret[SHARED_SECRET_LENGTH];
+} obfs2_config_t;
+
+typedef struct obfs2_conn_t {
+ conn_t super;
+ obfs2_state_t *state;
+} obfs2_conn_t;
#endif
1
0
09 Sep '11
commit 297439cd51903fa8010f83ffaec74b4eed755c24
Author: George Kadianakis <desnacked(a)gmail.com>
Date: Sat Aug 20 03:26:31 2011 +0200
...then revive the obfs2 unit tests as well.
---
src/test/unittest.c | 4 +-
src/test/unittest_obfs2.c | 108 ++++++++++++++++++++++----------------------
2 files changed, 56 insertions(+), 56 deletions(-)
diff --git a/src/test/unittest.c b/src/test/unittest.c
index 13557bf..5f2613c 100644
--- a/src/test/unittest.c
+++ b/src/test/unittest.c
@@ -9,14 +9,14 @@ extern struct testcase_t container_tests[];
extern struct testcase_t crypt_tests[];
extern struct testcase_t socks_tests[];
extern struct testcase_t dummy_tests[];
-/*extern struct testcase_t obfs2_tests[];*/
+extern struct testcase_t obfs2_tests[];
struct testgroup_t groups[] = {
{ "container/", container_tests },
{ "crypt/", crypt_tests },
{ "socks/", socks_tests },
{ "dummy/", dummy_tests },
- /*{ "obfs2/", obfs2_tests },*/
+ { "obfs2/", obfs2_tests },
END_OF_GROUPS
};
diff --git a/src/test/unittest_obfs2.c b/src/test/unittest_obfs2.c
index e5addcc..211f6af 100644
--- a/src/test/unittest_obfs2.c
+++ b/src/test/unittest_obfs2.c
@@ -14,17 +14,17 @@
#define ALEN(x) (sizeof x/sizeof x[0])
-static inline obfs2_protocol_t *
-downcast(protocol_t *proto)
+static inline obfs2_conn_t *
+downcast(conn_t *proto)
{
- return DOWNCAST(obfs2_protocol_t, super, proto);
+ return DOWNCAST(obfs2_conn_t, super, proto);
}
static void
test_obfs2_option_parsing(void *unused)
{
struct option_parsing_case {
- protocol_params_t *result;
+ config_t *result;
short should_succeed;
short n_opts;
const char *const opts[6];
@@ -58,7 +58,7 @@ test_obfs2_option_parsing(void *unused)
struct option_parsing_case *c;
for (c = cases; c->n_opts; c++) {
- c->result = proto_params_init(c->n_opts, c->opts);
+ c->result = config_create(c->n_opts, c->opts);
if (c->should_succeed)
tt_ptr_op(c->result, !=, NULL);
else
@@ -68,7 +68,7 @@ test_obfs2_option_parsing(void *unused)
end:
for (c = cases; c->n_opts; c++)
if (c->result)
- proto_params_free(c->result);
+ config_free(c->result);
/* Unsuspend logging */
log_set_method(LOG_METHOD_STDERR, NULL);
@@ -77,10 +77,10 @@ test_obfs2_option_parsing(void *unused)
/* All the tests below use this test environment: */
struct test_obfs2_state
{
- protocol_params_t *proto_params_client;
- protocol_params_t *proto_params_server;
- protocol_t *client_proto;
- protocol_t *server_proto;
+ config_t *cfg_client;
+ config_t *cfg_server;
+ conn_t *conn_client;
+ conn_t *conn_server;
struct evbuffer *output_buffer;
struct evbuffer *dummy_buffer;
};
@@ -90,15 +90,15 @@ cleanup_obfs2_state(const struct testcase_t *unused, void *state)
{
struct test_obfs2_state *s = (struct test_obfs2_state *)state;
- if (s->client_proto)
- proto_destroy(s->client_proto);
- if (s->server_proto)
- proto_destroy(s->server_proto);
+ if (s->conn_client)
+ proto_conn_free(s->conn_client);
+ if (s->conn_server)
+ proto_conn_free(s->conn_server);
- if (s->proto_params_client)
- proto_params_free(s->proto_params_client);
- if (s->proto_params_server)
- proto_params_free(s->proto_params_server);
+ if (s->cfg_client)
+ config_free(s->cfg_client);
+ if (s->cfg_server)
+ config_free(s->cfg_server);
if (s->output_buffer)
evbuffer_free(s->output_buffer);
@@ -121,19 +121,19 @@ setup_obfs2_state(const struct testcase_t *unused)
{
struct test_obfs2_state *s = xzalloc(sizeof(struct test_obfs2_state));
- s->proto_params_client =
- proto_params_init(ALEN(options_client), options_client);
- tt_assert(s->proto_params_client);
+ s->cfg_client =
+ config_create(ALEN(options_client), options_client);
+ tt_assert(s->cfg_client);
- s->proto_params_server =
- proto_params_init(ALEN(options_server), options_server);
- tt_assert(s->proto_params_server);
+ s->cfg_server =
+ config_create(ALEN(options_server), options_server);
+ tt_assert(s->cfg_server);
- s->client_proto = proto_create(s->proto_params_client);
- tt_assert(s->client_proto);
+ s->conn_client = proto_conn_create(s->cfg_client);
+ tt_assert(s->conn_client);
- s->server_proto = proto_create(s->proto_params_server);
- tt_assert(s->server_proto);
+ s->conn_server = proto_conn_create(s->cfg_server);
+ tt_assert(s->conn_server);
s->output_buffer = evbuffer_new();
tt_assert(s->output_buffer);
@@ -155,22 +155,22 @@ static void
test_obfs2_handshake(void *state)
{
struct test_obfs2_state *s = (struct test_obfs2_state *)state;
- obfs2_protocol_t *client_state = downcast(s->client_proto);
- obfs2_protocol_t *server_state = downcast(s->server_proto);
+ obfs2_state_t *client_state = downcast(s->conn_client)->state;
+ obfs2_state_t *server_state = downcast(s->conn_server)->state;
/* We create a client handshake message and pass it to output_buffer */
- tt_int_op(0, <=, proto_handshake(s->client_proto, s->output_buffer));
+ tt_int_op(0, <=, proto_handshake(s->conn_client, s->output_buffer));
/* We simulate the server receiving and processing the client's
handshake message, by using proto_recv() on the output_buffer */
- tt_assert(RECV_GOOD == proto_recv(s->server_proto, s->output_buffer,
+ tt_assert(RECV_GOOD == proto_recv(s->conn_server, s->output_buffer,
s->dummy_buffer));
/* Now, we create the server's handshake and pass it to output_buffer */
- tt_int_op(0, <=, proto_handshake(s->server_proto, s->output_buffer));
+ tt_int_op(0, <=, proto_handshake(s->conn_server, s->output_buffer));
/* We simulate the client receiving and processing the server's handshake */
- tt_assert(RECV_GOOD == proto_recv(s->client_proto, s->output_buffer,
+ tt_assert(RECV_GOOD == proto_recv(s->conn_client, s->output_buffer,
s->dummy_buffer));
/* The handshake is now complete. We should have:
@@ -193,11 +193,11 @@ test_obfs2_transfer(void *state)
struct evbuffer_iovec v[2];
/* Handshake */
- tt_int_op(0, <=, proto_handshake(s->client_proto, s->output_buffer));
- tt_assert(RECV_GOOD == proto_recv(s->server_proto, s->output_buffer,
+ tt_int_op(0, <=, proto_handshake(s->conn_client, s->output_buffer));
+ tt_assert(RECV_GOOD == proto_recv(s->conn_server, s->output_buffer,
s->dummy_buffer));
- tt_int_op(0, <=, proto_handshake(s->server_proto, s->output_buffer));
- tt_assert(RECV_GOOD == proto_recv(s->client_proto, s->output_buffer,
+ tt_int_op(0, <=, proto_handshake(s->conn_server, s->output_buffer));
+ tt_assert(RECV_GOOD == proto_recv(s->conn_client, s->output_buffer,
s->dummy_buffer));
/* End of Handshake */
@@ -207,9 +207,9 @@ test_obfs2_transfer(void *state)
/* client -> server */
evbuffer_add(s->dummy_buffer, msg1, 54);
- proto_send(s->client_proto, s->dummy_buffer, s->output_buffer);
+ proto_send(s->conn_client, s->dummy_buffer, s->output_buffer);
- tt_assert(RECV_GOOD == proto_recv(s->server_proto, s->output_buffer,
+ tt_assert(RECV_GOOD == proto_recv(s->conn_server, s->output_buffer,
s->dummy_buffer));
n = evbuffer_peek(s->dummy_buffer, -1, NULL, &v[0], 2);
@@ -222,10 +222,10 @@ test_obfs2_transfer(void *state)
/* client <- server */
evbuffer_add(s->dummy_buffer, msg2, 55);
- tt_int_op(0, <=, proto_send(s->server_proto, s->dummy_buffer,
+ tt_int_op(0, <=, proto_send(s->conn_server, s->dummy_buffer,
s->output_buffer));
- tt_assert(RECV_GOOD == proto_recv(s->client_proto, s->output_buffer,
+ tt_assert(RECV_GOOD == proto_recv(s->conn_client, s->output_buffer,
s->dummy_buffer));
n = evbuffer_peek(s->dummy_buffer, -1, NULL, &v[1], 2);
@@ -249,8 +249,8 @@ static void
test_obfs2_split_handshake(void *state)
{
struct test_obfs2_state *s = (struct test_obfs2_state *)state;
- obfs2_protocol_t *client_state = downcast(s->client_proto);
- obfs2_protocol_t *server_state = downcast(s->server_proto);
+ obfs2_state_t *client_state = downcast(s->conn_client)->state;
+ obfs2_state_t *server_state = downcast(s->conn_server)->state;
uint32_t magic = htonl(OBFUSCATE_MAGIC_VALUE);
uint32_t plength1, plength1_msg1, plength1_msg2, send_plength1;
@@ -285,7 +285,7 @@ test_obfs2_split_handshake(void *state)
OBFUSCATE_SEED_LENGTH+8+plength1_msg1);
/* Server receives handshake part 1 */
- tt_assert(RECV_INCOMPLETE == proto_recv(s->server_proto, s->output_buffer,
+ tt_assert(RECV_INCOMPLETE == proto_recv(s->conn_server, s->output_buffer,
s->dummy_buffer));
tt_assert(server_state->state == ST_WAIT_FOR_PADDING);
@@ -298,7 +298,7 @@ test_obfs2_split_handshake(void *state)
evbuffer_add(s->output_buffer, msgclient_2, plength1_msg2);
/* Server receives handshake part 2 */
- tt_assert(RECV_GOOD == proto_recv(s->server_proto, s->output_buffer,
+ tt_assert(RECV_GOOD == proto_recv(s->conn_server, s->output_buffer,
s->dummy_buffer));
tt_assert(server_state->state == ST_OPEN);
@@ -329,7 +329,7 @@ test_obfs2_split_handshake(void *state)
evbuffer_add(s->output_buffer, msgserver_1, OBFUSCATE_SEED_LENGTH+8);
/* Client receives handshake part 1 */
- tt_assert(RECV_INCOMPLETE == proto_recv(s->client_proto, s->output_buffer,
+ tt_assert(RECV_INCOMPLETE == proto_recv(s->conn_client, s->output_buffer,
s->dummy_buffer));
tt_assert(client_state->state == ST_WAIT_FOR_PADDING);
@@ -342,7 +342,7 @@ test_obfs2_split_handshake(void *state)
evbuffer_add(s->output_buffer, msgserver_2, plength2);
/* Client receives handshake part 2 */
- tt_assert(RECV_GOOD == proto_recv(s->client_proto, s->output_buffer,
+ tt_assert(RECV_GOOD == proto_recv(s->conn_client, s->output_buffer,
s->dummy_buffer));
tt_assert(client_state->state == ST_OPEN);
@@ -367,8 +367,8 @@ static void
test_obfs2_wrong_handshake_magic(void *state)
{
struct test_obfs2_state *s = (struct test_obfs2_state *)state;
- obfs2_protocol_t *client_state = downcast(s->client_proto);
- obfs2_protocol_t *server_state = downcast(s->server_proto);
+ obfs2_state_t *client_state = downcast(s->conn_client)->state;
+ obfs2_state_t *server_state = downcast(s->conn_server)->state;
uint32_t wrong_magic = 0xD15EA5E;
@@ -391,7 +391,7 @@ test_obfs2_wrong_handshake_magic(void *state)
evbuffer_add(s->output_buffer, msg, OBFUSCATE_SEED_LENGTH+8+plength);
- tt_assert(RECV_BAD == proto_recv(s->server_proto, s->output_buffer,
+ tt_assert(RECV_BAD == proto_recv(s->conn_server, s->output_buffer,
s->dummy_buffer));
tt_assert(server_state->state == ST_WAIT_FOR_KEY);
@@ -406,8 +406,8 @@ static void
test_obfs2_wrong_handshake_plength(void *state)
{
struct test_obfs2_state *s = (struct test_obfs2_state *)state;
- obfs2_protocol_t *client_state = downcast(s->client_proto);
- obfs2_protocol_t *server_state = downcast(s->server_proto);
+ obfs2_state_t *client_state = downcast(s->conn_client)->state;
+ obfs2_state_t *server_state = downcast(s->conn_server)->state;
uchar msg[OBFUSCATE_MAX_PADDING + OBFUSCATE_SEED_LENGTH + 8 + 1];
uint32_t magic = htonl(OBFUSCATE_MAGIC_VALUE);
@@ -429,7 +429,7 @@ test_obfs2_wrong_handshake_plength(void *state)
evbuffer_add(s->output_buffer, msg, OBFUSCATE_SEED_LENGTH+8+plength);
- tt_assert(RECV_BAD == proto_recv(s->server_proto, s->output_buffer,
+ tt_assert(RECV_BAD == proto_recv(s->conn_server, s->output_buffer,
s->dummy_buffer));
tt_assert(server_state->state == ST_WAIT_FOR_KEY);
1
0
[obfsproxy/master] Fix a problem when receiving test files in tester.py.
by nickm@torproject.org 09 Sep '11
by nickm@torproject.org 09 Sep '11
09 Sep '11
commit fb876074f1c040a6bdcf0e7489ca5e07d5ce428f
Author: George Kadianakis <desnacked(a)gmail.com>
Date: Fri Aug 19 05:29:09 2011 +0200
Fix a problem when receiving test files in tester.py.
The workers of tester.py used to socket.recv() till they got
zero-length data. That's usually caused by "EOF" or by the other side
of the socket closing.
A python string (TEST_FILE) don't cause an "EOF" and obfsproxy doesn't
close its sockets since it's supposed to stream data continuously. So,
how did the integration tests work?
tester.py used to socket.shutdown(socket.SHUT_WR) the upstream part of
the connection right after sending the test file, which resulted in
obfsproxy conn_free'ing the whole 'circuit'; including the downstream
side. That used to return zero-length data to recv() and that's how it
was getting out of the ReadWorker:work().
In the case of handshake-less protocols (like 'dummy') that was okay,
since the data were ultimately transferred to the server's destination
by conn_flush_and_free()s.
The thing is that in protocols like obfs2, the handshake couldn't be
completed since the whole 'circuit' was torn down. And that's why
obfs2 tests did not work.
This patch uses socket.timeout instead of zero-length data to get out
of the recv() loop.
Conflicts:
src/test/tester.py.in
---
src/test/tester.py.in | 45 ++++++++++++++++++++++++++-------------------
1 files changed, 26 insertions(+), 19 deletions(-)
diff --git a/src/test/tester.py.in b/src/test/tester.py.in
index 55d9477..4b93784 100644
--- a/src/test/tester.py.in
+++ b/src/test/tester.py.in
@@ -102,6 +102,8 @@ def connect_with_retry(addr):
retry += 1
time.sleep(0.05)
+SOCKET_TIMEOUT = 1.0
+
# Helper: In a separate process (to avoid deadlock), listen on a
# specified socket. The first time something connects to that socket,
# read all available data, stick it in a string, and post the string
@@ -116,13 +118,15 @@ class ReadWorker(object):
listener.listen(1)
(conn, remote) = listener.accept()
listener.close()
- conn.settimeout(1.0)
+ conn.settimeout(SOCKET_TIMEOUT)
data = ""
try:
while True:
chunk = conn.recv(4096)
if chunk == "": break
data += chunk
+ except socket.timeout:
+ pass
except Exception, e:
data += "|RECV ERROR: " + e
conn.close()
@@ -135,7 +139,7 @@ class ReadWorker(object):
self.worker.start()
def get(self):
- rv = self.oq.get(timeout=1)
+ rv = self.oq.get(timeout=SOCKET_TIMEOUT+0.1)
self.worker.join()
return rv
@@ -162,7 +166,7 @@ class DirectTest(object):
self.output_reader = ReadWorker(("127.0.0.1", EXIT_PORT))
self.obfs = Obfsproxy(self.obfs_args)
self.input_chan = connect_with_retry(("127.0.0.1", ENTRY_PORT))
- self.input_chan.settimeout(1.0)
+ self.input_chan.settimeout(SOCKET_TIMEOUT)
def tearDown(self):
self.obfs.stop()
@@ -174,12 +178,13 @@ class DirectTest(object):
# transfer a file. Then check whether the output is the same
# as the input.
self.input_chan.sendall(TEST_FILE)
- self.input_chan.shutdown(socket.SHUT_WR)
try:
output = self.output_reader.get()
except Queue.Empty:
output = ""
+ self.input_chan.close()
+
report = diff("errors in transfer:", TEST_FILE, output)
report += self.obfs.check_completion("obfsproxy", report!="")
@@ -243,20 +248,22 @@ class SocksTest(object):
if e.errno != errno.ECONNRESET: raise
self.assertEqual(got, exp)
sending = not sending
+
if good:
input_chan.sendall(TEST_FILE)
- input_chan.shutdown(socket.SHUT_WR)
try:
output = self.output_reader.get()
except Queue.Empty:
output = ""
+ input_chan.close()
+
if good: return output
else: return None
def socksTest(self, sequence):
input_chan = connect_with_retry(("127.0.0.1", ENTRY_PORT))
- input_chan.settimeout(1.0)
+ input_chan.settimeout(SOCKET_TIMEOUT)
try:
output = self.socksTestInner(sequence, input_chan)
@@ -352,13 +359,13 @@ class SocksBad(SocksTest, unittest.TestCase):
#
# fails, disabled
-#class DirectObfs2(DirectTest, unittest.TestCase):
-# obfs_args = ("obfs2",
-# "--dest=127.0.0.1:%d" % EXIT_PORT,
-# "server", "127.0.0.1:%d" % SERVER_PORT,
-# "obfs2",
-# "--dest=127.0.0.1:%d" % SERVER_PORT,
-# "client", "127.0.0.1:%d" % ENTRY_PORT)
+class DirectObfs2(DirectTest, unittest.TestCase):
+ obfs_args = ("obfs2",
+ "--dest=127.0.0.1:%d" % EXIT_PORT,
+ "server", "127.0.0.1:%d" % SERVER_PORT,
+ "obfs2",
+ "--dest=127.0.0.1:%d" % SERVER_PORT,
+ "client", "127.0.0.1:%d" % ENTRY_PORT)
class DirectDummy(DirectTest, unittest.TestCase):
obfs_args = ("dummy", "server",
@@ -369,12 +376,12 @@ class DirectDummy(DirectTest, unittest.TestCase):
"127.0.0.1:%d" % SERVER_PORT)
# fails, disabled
-#class SocksObfs2(GoodSocksTest, unittest.TestCase):
-# server_args = ("obfs2",
-# "--dest=127.0.0.1:%d" % EXIT_PORT,
-# "server", "127.0.0.1:%d" % SERVER_PORT)
-# client_args = ("obfs2",
-# "socks", "127.0.0.1:%d" % ENTRY_PORT)
+class SocksObfs2(GoodSocksTest, unittest.TestCase):
+ server_args = ("obfs2",
+ "--dest=127.0.0.1:%d" % EXIT_PORT,
+ "server", "127.0.0.1:%d" % SERVER_PORT)
+ client_args = ("obfs2",
+ "socks", "127.0.0.1:%d" % ENTRY_PORT)
class SocksDummy(GoodSocksTest, unittest.TestCase):
server_args = ("dummy", "server",
1
0
[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
by nickm@torproject.org 09 Sep '11
by nickm@torproject.org 09 Sep '11
09 Sep '11
commit d0cf5ae1f52fc3bf9daa4c3fb754cc77e4b74159
Author: Zack Weinberg <zackw(a)panix.com>
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;
1
0
commit c711fdc130f6e6a388b88273151c77711c72adcb
Author: Zack Weinberg <zackw(a)panix.com>
Date: Mon Jul 25 11:13:13 2011 -0700
Change some names around
---
src/network.c | 48 +++++++++++++++++++++++++-----------------------
1 files changed, 25 insertions(+), 23 deletions(-)
diff --git a/src/network.c b/src/network.c
index 3337aed..31a7013 100644
--- a/src/network.c
+++ b/src/network.c
@@ -51,11 +51,11 @@ static void conn_free(conn_t *conn);
static void close_all_connections(void);
static void close_conn_on_flush(struct bufferevent *bev, void *arg);
-static void plaintext_read_cb(struct bufferevent *bev, void *arg);
+
+static void upstream_read_cb(struct bufferevent *bev, void *arg);
+static void downstream_read_cb(struct bufferevent *bev, void *arg);
static void socks_read_cb(struct bufferevent *bev, void *arg);
-/* ASN Changed encrypted_read_cb() to obfuscated_read_cb(), it sounds
- a bit more obfsproxy generic. I still don't like it though. */
-static void obfuscated_read_cb(struct bufferevent *bev, void *arg);
+
static void input_event_cb(struct bufferevent *bev, short what, void *arg);
static void output_event_cb(struct bufferevent *bev, short what, void *arg);
static void socks_event_cb(struct bufferevent *bev, short what, void *arg);
@@ -213,12 +213,12 @@ simple_client_listener_cb(struct evconnlistener *evcl,
if (!conn->output)
goto err;
- bufferevent_setcb(conn->input, plaintext_read_cb, NULL, input_event_cb, conn);
+ bufferevent_setcb(conn->input, upstream_read_cb, NULL, input_event_cb, conn);
/* don't enable the input side for reading at this point; wait till we
have a connection to the target */
bufferevent_setcb(conn->output,
- obfuscated_read_cb, NULL, output_event_cb, conn);
+ downstream_read_cb, NULL, output_event_cb, conn);
/* Queue handshake, if any, before connecting. */
if (proto_handshake(conn->proto, bufferevent_get_output(conn->output)) < 0)
@@ -335,7 +335,7 @@ simple_server_listener_cb(struct evconnlistener *evcl,
goto err;
fd = -1; /* prevent double-close */
- bufferevent_setcb(conn->input, obfuscated_read_cb, NULL, input_event_cb, conn);
+ bufferevent_setcb(conn->input, downstream_read_cb, NULL, input_event_cb, conn);
/* don't enable the input side for reading at this point; wait till we
have a connection to the target */
@@ -345,7 +345,7 @@ simple_server_listener_cb(struct evconnlistener *evcl,
if (!conn->output)
goto err;
- bufferevent_setcb(conn->output, plaintext_read_cb, NULL,
+ bufferevent_setcb(conn->output, upstream_read_cb, NULL,
output_event_cb, conn);
/* Queue handshake, if any, before connecting. */
@@ -456,7 +456,7 @@ socks_read_cb(struct bufferevent *bev, void *arg)
-1,
BEV_OPT_CLOSE_ON_FREE);
- bufferevent_setcb(conn->output, obfuscated_read_cb, NULL,
+ bufferevent_setcb(conn->output, downstream_read_cb, NULL,
socks_event_cb, conn);
/* Queue handshake, if any, before connecting. */
@@ -503,16 +503,18 @@ socks_read_cb(struct bufferevent *bev, void *arg)
}
/**
- This callback is responsible for handling plaintext traffic.
-*/
+ This callback is responsible for handling "upstream" traffic --
+ traffic coming in from the higher-level client or server that needs
+ to be obfuscated and transmitted.
+ */
static void
-plaintext_read_cb(struct bufferevent *bev, void *arg)
+upstream_read_cb(struct bufferevent *bev, void *arg)
{
conn_t *conn = arg;
struct bufferevent *other;
other = (bev == conn->input) ? conn->output : conn->input;
- log_debug("Got data on plaintext side");
+ log_debug("Got data on upstream side");
if (proto_send(conn->proto,
bufferevent_get_input(bev),
bufferevent_get_output(other)) < 0)
@@ -520,19 +522,19 @@ plaintext_read_cb(struct bufferevent *bev, void *arg)
}
/**
- This callback is responsible for handling obfuscated
- traffic -- traffic that has already been obfuscated
- by our protocol.
-*/
+ This callback is responsible for handling "downstream" traffic --
+ traffic coming in from our remote peer that needs to be deobfuscated
+ and passed to the upstream client or server.
+ */
static void
-obfuscated_read_cb(struct bufferevent *bev, void *arg)
+downstream_read_cb(struct bufferevent *bev, void *arg)
{
conn_t *conn = arg;
struct bufferevent *other;
other = (bev == conn->input) ? conn->output : conn->input;
enum recv_ret r;
- log_debug("Got data on encrypted side");
+ log_debug("Got data on downstream side");
r = proto_recv(conn->proto,
bufferevent_get_input(bev),
bufferevent_get_output(other));
@@ -548,7 +550,7 @@ obfuscated_read_cb(struct bufferevent *bev, void *arg)
/**
Something broke in our connection or we reached EOF.
We prepare the connection to be closed ASAP.
-*/
+ */
static void
error_or_eof(conn_t *conn,
struct bufferevent *bev_err, struct bufferevent *bev_flush)
@@ -675,11 +677,11 @@ socks_event_cb(struct bufferevent *bev, short what, void *arg)
socks_state_free(conn->socks_state);
conn->socks_state = NULL;
bufferevent_setcb(conn->input,
- plaintext_read_cb, NULL, input_event_cb, conn);
+ upstream_read_cb, NULL, input_event_cb, conn);
bufferevent_setcb(conn->output,
- obfuscated_read_cb, NULL, output_event_cb, conn);
+ downstream_read_cb, NULL, output_event_cb, conn);
if (evbuffer_get_length(bufferevent_get_input(conn->input)) != 0)
- obfuscated_read_cb(bev, conn->input);
+ downstream_read_cb(bev, conn->input);
}
/* also do everything that's done on a normal connection */
1
0
[obfsproxy/master] Use 'upstream' and 'downstream' for the two sides of a connection, not 'input' and 'output'.
by nickm@torproject.org 09 Sep '11
by nickm@torproject.org 09 Sep '11
09 Sep '11
commit 234c332b78cccbdf05316d2d38cc9e635f37df11
Author: Zack Weinberg <zackw(a)panix.com>
Date: Mon Jul 25 15:06:41 2011 -0700
Use 'upstream' and 'downstream' for the two sides of a connection, not 'input' and 'output'.
---
src/network.c | 195 ++++++++++++++++++++++++++++++++++-----------------------
src/network.h | 4 +-
2 files changed, 118 insertions(+), 81 deletions(-)
diff --git a/src/network.c b/src/network.c
index f3d09cf..9003ea9 100644
--- a/src/network.c
+++ b/src/network.c
@@ -26,6 +26,35 @@
#include <ws2tcpip.h> /* socklen_t */
#endif
+/* Terminology used in this file:
+
+ A "side" is a bidirectional communications channel, usually backed
+ by a network socket and represented at this layer by a
+ 'struct bufferevent'.
+
+ A "connection" is a _pair_ of sides, referred to as the "upstream"
+ side and the "downstream" side. A connection is represented by a
+ 'conn_t'. The upstream side of a connection communicates in
+ cleartext with the higher-level program that wishes to make use of
+ our obfuscation service. The downstream side commmunicates in an
+ obfuscated fashion with the remote peer that the higher-level
+ client wishes to contact.
+
+ A "listener" is a listening socket bound to a particular
+ obfuscation protocol, represented in this layer by a 'listener_t'.
+ Connecting to a listener creates one side of a connection, and
+ causes this program to initiate the other side of the connection.
+ A listener is said to be a "client" listener if connecting to it
+ creates the _upstream_ side of a connection, and a "server"
+ listener if connecting to it creates the _downstream_ side.
+
+ There are two kinds of client listeners: a "simple" client listener
+ always connects to the same remote peer every time it needs to
+ initiate a downstream connection; a "socks" client listener can be
+ told to connect to an arbitrary remote peer using the SOCKS protocol
+ (version 4 or 5).
+*/
+
/** All our listeners. */
static smartlist_t *listeners;
@@ -205,34 +234,37 @@ simple_client_listener_cb(struct evconnlistener *evcl,
/* 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)
+ conn->upstream = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
+ if (!conn->upstream)
goto err;
fd = -1; /* prevent double-close */
+ bufferevent_setcb(conn->upstream,
+ upstream_read_cb, NULL, error_cb, conn);
+
+ /* Don't enable the upstream side for reading at this point; wait
+ till the downstream side is established. */
+
/* New bufferevent to connect to the target address */
- conn->output = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
- if (!conn->output)
+ conn->downstream = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
+ if (!conn->downstream)
goto err;
- bufferevent_setcb(conn->input, upstream_read_cb, NULL, error_cb, conn);
- /* don't enable the input side for reading at this point; wait till we
- have a connection to the target */
-
- bufferevent_setcb(conn->output,
+ bufferevent_setcb(conn->downstream,
downstream_read_cb, NULL, pending_conn_cb, conn);
/* Queue handshake, if any, before connecting. */
- if (proto_handshake(conn->proto, bufferevent_get_output(conn->output)) < 0)
+ if (proto_handshake(conn->proto,
+ bufferevent_get_output(conn->downstream))<0)
goto err;
/* Launch the connect attempt. */
- if (bufferevent_socket_connect(conn->output,
+ if (bufferevent_socket_connect(conn->downstream,
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->downstream, EV_READ|EV_WRITE);
/* add conn to the connection list */
if (!connections)
@@ -279,16 +311,16 @@ socks_client_listener_cb(struct evconnlistener *evcl,
/* 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)
+ conn->upstream = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
+ if (!conn->upstream)
goto err;
fd = -1; /* prevent double-close */
- bufferevent_setcb(conn->input, socks_read_cb, NULL, error_cb, conn);
- bufferevent_enable(conn->input, EV_READ|EV_WRITE);
+ bufferevent_setcb(conn->upstream, socks_read_cb, NULL, error_cb, conn);
+ bufferevent_enable(conn->upstream, EV_READ|EV_WRITE);
- /* Do not create an output bufferevent at this time; the socks
- handler will do it after we know where we're connecting */
+ /* Do not create a downstream bufferevent at this time; the socks
+ handler will do it after it learns the downstream peer address. */
/* add conn to the connection list */
if (!connections)
@@ -332,43 +364,45 @@ simple_server_listener_cb(struct evconnlistener *evcl,
/* 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)
+ conn->downstream = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE);
+ if (!conn->downstream)
goto err;
fd = -1; /* prevent double-close */
- bufferevent_setcb(conn->input, downstream_read_cb, NULL, error_cb, conn);
+ bufferevent_setcb(conn->downstream,
+ downstream_read_cb, NULL, error_cb, conn);
- /* don't enable the input side for reading at this point; wait till we
- have a connection to the target */
+ /* Don't enable the downstream side for reading at this point; wait
+ till the upstream side is established. */
- /* New bufferevent to connect to the target address */
- conn->output = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
- if (!conn->output)
+ /* New bufferevent to connect to the target address. */
+ conn->upstream = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
+ if (!conn->upstream)
goto err;
- bufferevent_setcb(conn->output, upstream_read_cb, NULL,
- pending_conn_cb, conn);
+ bufferevent_setcb(conn->upstream,
+ upstream_read_cb, NULL, pending_conn_cb, conn);
/* Queue handshake, if any, before connecting. */
if (proto_handshake(conn->proto,
- bufferevent_get_output(conn->input))<0)
+ bufferevent_get_output(conn->upstream))<0)
goto err;
- if (bufferevent_socket_connect(conn->output,
+ /* Launch the connect attempt. */
+ if (bufferevent_socket_connect(conn->upstream,
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->upstream, EV_READ|EV_WRITE);
/* add conn to the connection list */
if (!connections)
connections = smartlist_create();
smartlist_add(connections, conn);
- log_debug("Connection setup completed. "
- "We currently have %d connections!", smartlist_len(connections));
+ log_debug("%s: setup completed, %d connections",
+ __func__, smartlist_len(connections));
return;
err:
@@ -388,10 +422,10 @@ conn_free(conn_t *conn)
proto_destroy(conn->proto);
if (conn->socks_state)
socks_state_free(conn->socks_state);
- if (conn->input)
- bufferevent_free(conn->input);
- if (conn->output)
- bufferevent_free(conn->output);
+ if (conn->upstream)
+ bufferevent_free(conn->upstream);
+ if (conn->upstream)
+ bufferevent_free(conn->upstream);
memset(conn, 0x99, sizeof(conn_t));
free(conn);
@@ -409,8 +443,8 @@ close_conn(conn_t *conn)
log_debug("Connection destroyed. "
"We currently have %d connections!", smartlist_len(connections));
- /** If this was the last connection AND we are shutting down,
- finish shutdown. */
+ /* If this was the last connection AND we are shutting down,
+ finish shutdown. */
if (smartlist_len(connections) == 0) {
smartlist_free(connections);
connections = NULL;
@@ -440,9 +474,9 @@ static void
socks_read_cb(struct bufferevent *bev, void *arg)
{
conn_t *conn = arg;
- //struct bufferevent *other;
enum socks_ret socks_ret;
- obfs_assert(bev == conn->input); /* socks only makes sense on the input side */
+ /* socks only makes sense on the upstream side */
+ obfs_assert(bev == conn->upstream);
do {
enum socks_status_t status = socks_state_get_status(conn->socks_state);
@@ -454,25 +488,25 @@ 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);
+ conn->downstream =
+ bufferevent_socket_new(bufferevent_get_base(conn->upstream),
+ -1, BEV_OPT_CLOSE_ON_FREE);
- bufferevent_setcb(conn->output, downstream_read_cb, NULL,
- pending_socks_cb, conn);
+ bufferevent_setcb(conn->downstream,
+ downstream_read_cb, NULL, pending_socks_cb, conn);
/* Queue handshake, if any, before connecting. */
if (proto_handshake(conn->proto,
- bufferevent_get_output(conn->output))<0) {
+ bufferevent_get_output(conn->downstream))<0) {
/* XXXX send socks reply */
close_conn(conn);
return;
}
- r = bufferevent_socket_connect_hostname(conn->output,
+ r = bufferevent_socket_connect_hostname(conn->downstream,
get_evdns_base(),
af, addr, port);
- bufferevent_enable(conn->output, EV_READ|EV_WRITE);
+ bufferevent_enable(conn->downstream, EV_READ|EV_WRITE);
log_debug("socket_connect_hostname said %d! (%s,%d)", r, addr, port);
if (r < 0) {
@@ -480,13 +514,15 @@ socks_read_cb(struct bufferevent *bev, void *arg)
close_conn(conn);
return;
}
- bufferevent_disable(conn->input, EV_READ|EV_WRITE);
- /* ignore data XXX */
+ /* further upstream data will be processed once the downstream
+ side is established */
+ bufferevent_disable(conn->upstream, EV_READ|EV_WRITE);
return;
}
socks_ret = handle_socks(bufferevent_get_input(bev),
- bufferevent_get_output(bev), conn->socks_state);
+ bufferevent_get_output(bev),
+ conn->socks_state);
} while (socks_ret == SOCKS_GOOD);
if (socks_ret == SOCKS_INCOMPLETE)
@@ -513,13 +549,12 @@ static void
upstream_read_cb(struct bufferevent *bev, void *arg)
{
conn_t *conn = arg;
- struct bufferevent *other;
- other = (bev == conn->input) ? conn->output : conn->input;
+ obfs_assert(bev == conn->upstream);
log_debug("Got data on upstream side");
if (proto_send(conn->proto,
- bufferevent_get_input(bev),
- bufferevent_get_output(other)) < 0)
+ bufferevent_get_input(conn->upstream),
+ bufferevent_get_output(conn->downstream)) < 0)
close_conn(conn);
}
@@ -532,25 +567,24 @@ static void
downstream_read_cb(struct bufferevent *bev, void *arg)
{
conn_t *conn = arg;
- struct bufferevent *other;
- other = (bev == conn->input) ? conn->output : conn->input;
enum recv_ret r;
+ obfs_assert(bev == conn->downstream);
log_debug("Got data on downstream side");
r = proto_recv(conn->proto,
- bufferevent_get_input(bev),
- bufferevent_get_output(other));
+ bufferevent_get_input(conn->downstream),
+ bufferevent_get_output(conn->upstream));
if (r == RECV_BAD)
close_conn(conn);
else if (r == RECV_SEND_PENDING)
proto_send(conn->proto,
- bufferevent_get_input(conn->input),
- bufferevent_get_output(conn->output));
+ bufferevent_get_input(conn->upstream),
+ bufferevent_get_output(conn->downstream));
}
/**
- Something broke in our connection or we reached EOF.
+ Something broke one side of the connection, or we reached EOF.
We prepare the connection to be closed ASAP.
*/
static void
@@ -558,8 +592,8 @@ error_or_eof(conn_t *conn, struct bufferevent *bev_err)
{
struct bufferevent *bev_flush;
- if (bev_err == conn->input) bev_flush = conn->output;
- else if (bev_err == conn->output) bev_flush = conn->input;
+ if (bev_err == conn->upstream) bev_flush = conn->downstream;
+ else if (bev_err == conn->downstream) bev_flush = conn->upstream;
else obfs_abort();
log_debug("error_or_eof");
@@ -619,7 +653,7 @@ flush_error_cb(struct bufferevent *bev, short what, void *arg)
}
/**
- Called when an "event" happens on a socket that's still waiting to
+ Called when an event happens on a socket that's still waiting to
be connected. We expect to get BEV_EVENT_CONNECTED, which
indicates that the connection is now open, but we might also get
errors as above.
@@ -629,8 +663,8 @@ pending_conn_cb(struct bufferevent *bev, short what, void *arg)
{
conn_t *conn = arg;
struct bufferevent *other;
- if (bev == conn->input) other = conn->output;
- else if (bev == conn->output) other = conn->input;
+ if (bev == conn->upstream) other = conn->downstream;
+ else if (bev == conn->downstream) other = conn->upstream;
else obfs_abort();
/* Upon successful connection, enable traffic on the other side,
@@ -639,7 +673,7 @@ pending_conn_cb(struct bufferevent *bev, short what, void *arg)
obfs_assert(!conn->flushing);
conn->is_open = 1;
- log_debug("Connection successful") ;
+ log_debug("Connection successful");
bufferevent_enable(other, EV_READ|EV_WRITE);
/* XXX Dirty access to bufferevent guts. There appears to be no
@@ -654,15 +688,15 @@ pending_conn_cb(struct bufferevent *bev, short what, void *arg)
}
/**
- Called when an "event" happens on a socket in socks mode.
+ Called when an event happens on a socket in socks mode.
Both connections and errors are possible; must generate
- appropriate socks messages on the input side.
+ appropriate socks messages on the upstream side.
*/
static void
pending_socks_cb(struct bufferevent *bev, short what, void *arg)
{
conn_t *conn = arg;
- obfs_assert(bev == conn->output);
+ obfs_assert(bev == conn->downstream);
obfs_assert(conn->socks_state);
/* If we got an error while in the ST_HAVE_ADDR state, chances are
@@ -674,7 +708,8 @@ pending_socks_cb(struct bufferevent *bev, short what, void *arg)
log_warn("Connection error: %s",
evutil_socket_error_to_string(err));
if (socks_state_get_status(conn->socks_state) == ST_HAVE_ADDR) {
- socks_send_reply(conn->socks_state, bufferevent_get_output(conn->input),
+ socks_send_reply(conn->socks_state,
+ bufferevent_get_output(conn->upstream),
err);
}
error_or_eof(conn, bev);
@@ -697,7 +732,7 @@ pending_socks_cb(struct bufferevent *bev, short what, void *arg)
socks_state_set_address(conn->socks_state, sa);
}
socks_send_reply(conn->socks_state,
- bufferevent_get_output(conn->input), 0);
+ bufferevent_get_output(conn->upstream), 0);
/* Switch to regular upstream behavior. */
socks_state_free(conn->socks_state);
@@ -705,11 +740,13 @@ pending_socks_cb(struct bufferevent *bev, short what, void *arg)
conn->is_open = 1;
log_debug("Connection successful");
- bufferevent_setcb(conn->input, upstream_read_cb, NULL, error_cb, conn);
- bufferevent_setcb(conn->output, downstream_read_cb, NULL, error_cb, conn);
- bufferevent_enable(conn->input, EV_READ|EV_WRITE);
- if (evbuffer_get_length(bufferevent_get_input(conn->input)) != 0)
- downstream_read_cb(bev, conn->input);
+ bufferevent_setcb(conn->upstream,
+ upstream_read_cb, NULL, error_cb, conn);
+ bufferevent_setcb(conn->downstream,
+ downstream_read_cb, NULL, error_cb, conn);
+ bufferevent_enable(conn->upstream, EV_READ|EV_WRITE);
+ if (evbuffer_get_length(bufferevent_get_input(conn->upstream)) != 0)
+ downstream_read_cb(bev, conn->upstream);
return;
}
diff --git a/src/network.h b/src/network.h
index 49580c3..0d6ef8d 100644
--- a/src/network.h
+++ b/src/network.h
@@ -45,8 +45,8 @@ struct protocol_t;
typedef struct conn_t {
struct protocol_t *proto;
struct socks_state_t *socks_state;
- struct bufferevent *input;
- struct bufferevent *output;
+ struct bufferevent *upstream;
+ struct bufferevent *downstream;
unsigned int mode : 30;
unsigned int flushing : 1;
unsigned int is_open : 1;
1
0
[obfsproxy/master] Don't expose listener_t objects outside network.c.
by nickm@torproject.org 09 Sep '11
by nickm@torproject.org 09 Sep '11
09 Sep '11
commit 4b8ac430d0c7e7fea6e2ddb1d6ae71f87ac81edd
Author: Zack Weinberg <zackw(a)panix.com>
Date: Mon Jul 25 15:11:31 2011 -0700
Don't expose listener_t objects outside network.c.
---
src/main.c | 16 +++-------------
src/network.c | 22 +++++++---------------
src/network.h | 13 +++++++++----
3 files changed, 19 insertions(+), 32 deletions(-)
diff --git a/src/main.c b/src/main.c
index 254be94..cc69805 100644
--- a/src/main.c
+++ b/src/main.c
@@ -341,7 +341,6 @@ main(int argc, const char **argv)
/*Let's open a new listener for each protocol. */
int h;
- listener_t *temp_listener;
int n_listeners=0;
protocol_params_t *proto_params=NULL;
for (h=0;h<actual_protocols;h++) {
@@ -350,22 +349,13 @@ main(int argc, const char **argv)
/** normally free'd in listener_free() */
proto_params = proto_params_init(n_options_array[h],
(const char *const *)protocol_options[h]);
- if (!proto_params) {
- free(protocol_options[h]);
- continue;
+ if (proto_params && create_listener(the_event_base, proto_params)) {
+ log_info("Succesfully created listener %d.", h+1);
+ n_listeners++;
}
- temp_listener = listener_new(the_event_base, proto_params);
-
/** Free the space allocated for this protocol's options. */
free(protocol_options[h]);
-
- if (!temp_listener)
- continue;
-
- log_info("Succesfully created listener %d.", h+1);
-
- n_listeners++;
}
log_debug("From the original %d protocols only %d "
diff --git a/src/network.c b/src/network.c
index 9003ea9..c4cf0c7 100644
--- a/src/network.c
+++ b/src/network.c
@@ -58,11 +58,6 @@
/** All our listeners. */
static smartlist_t *listeners;
-struct listener_t {
- struct evconnlistener *listener;
- protocol_params_t *proto_params;
-};
-
/** All active connections. */
static smartlist_t *connections;
@@ -135,16 +130,13 @@ close_all_connections(void)
/**
This function spawns a listener configured according to the
- provided 'protocol_params_t' object'. Returns the listener on
- success, NULL on fail.
+ provided 'protocol_params_t' object'. Returns 1 on success, 0 on
+ failure. (No, you can't have the listener object. It's private.)
- If it succeeds, the new listener object takes ownership of the
- protocol_params_t object provided; if it fails, the protocol_params_t
- object is deallocated.
+ Regardless of success or failure, the protocol_params_t is consumed.
*/
-listener_t *
-listener_new(struct event_base *base,
- protocol_params_t *params)
+int
+create_listener(struct event_base *base, protocol_params_t *params)
{
const unsigned flags =
LEV_OPT_CLOSE_ON_FREE|LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_REUSEABLE;
@@ -168,7 +160,7 @@ listener_new(struct event_base *base,
log_warn("Failed to create listener!");
proto_params_free(params);
free(lsn);
- return NULL;
+ return 0;
}
/* If we don't have a listener list, create one now. */
@@ -176,7 +168,7 @@ listener_new(struct event_base *base,
listeners = smartlist_create();
smartlist_add(listeners, lsn);
- return lsn;
+ return 1;
}
/**
diff --git a/src/network.h b/src/network.h
index 0d6ef8d..b6aa410 100644
--- a/src/network.h
+++ b/src/network.h
@@ -28,10 +28,8 @@ enum recv_ret {
RECV_SEND_PENDING
};
-typedef struct listener_t listener_t;
-
-listener_t *listener_new(struct event_base *base,
- struct protocol_params_t *params);
+/* returns 1 on success, 0 on failure */
+int create_listener(struct event_base *base, struct protocol_params_t *params);
void free_all_listeners(void);
void start_shutdown(int barbaric);
@@ -39,8 +37,15 @@ void start_shutdown(int barbaric);
#ifdef NETWORK_PRIVATE
struct bufferevent;
+struct evconnlistener;
struct socks_state_t;
struct protocol_t;
+struct protocol_params_t;
+
+typedef struct listener_t {
+ struct evconnlistener *listener;
+ struct protocol_params_t *proto_params;
+} listener_t;
typedef struct conn_t {
struct protocol_t *proto;
1
0
[obfsproxy/master] Separate socks event handling from regular output-side event handling
by nickm@torproject.org 09 Sep '11
by nickm@torproject.org 09 Sep '11
09 Sep '11
commit 82a19273e86660c743bce5aed7c5ef8112dd5c01
Author: Zack Weinberg <zackw(a)panix.com>
Date: Mon Jul 25 11:01:46 2011 -0700
Separate socks event handling from regular output-side event handling
---
src/network.c | 176 ++++++++++++++++++++++++++++++++-------------------------
1 files changed, 98 insertions(+), 78 deletions(-)
diff --git a/src/network.c b/src/network.c
index 32d14ee..3337aed 100644
--- a/src/network.c
+++ b/src/network.c
@@ -58,6 +58,7 @@ static void socks_read_cb(struct bufferevent *bev, void *arg);
static void obfuscated_read_cb(struct bufferevent *bev, void *arg);
static void input_event_cb(struct bufferevent *bev, short what, void *arg);
static void output_event_cb(struct bufferevent *bev, short what, void *arg);
+static void socks_event_cb(struct bufferevent *bev, short what, void *arg);
/**
Puts obfsproxy's networking subsystem on "closing time" mode. This
@@ -213,12 +214,13 @@ simple_client_listener_cb(struct evconnlistener *evcl,
goto err;
bufferevent_setcb(conn->input, plaintext_read_cb, NULL, input_event_cb, conn);
- bufferevent_enable(conn->input, EV_READ|EV_WRITE);
+ /* don't enable the input side for reading at this point; wait till we
+ have a connection to the target */
bufferevent_setcb(conn->output,
obfuscated_read_cb, NULL, output_event_cb, conn);
- /* Queue output right now. */
+ /* Queue handshake, if any, before connecting. */
if (proto_handshake(conn->proto, bufferevent_get_output(conn->output)) < 0)
goto err;
@@ -283,7 +285,7 @@ socks_client_listener_cb(struct evconnlistener *evcl,
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
+ /* Do not create an output bufferevent at this time; the socks
handler will do it after we know where we're connecting */
/* add conn to the connection list */
@@ -334,7 +336,9 @@ simple_server_listener_cb(struct evconnlistener *evcl,
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);
+
+ /* don't enable the input side for reading at this point; wait till we
+ have a connection to the target */
/* New bufferevent to connect to the target address */
conn->output = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
@@ -436,8 +440,7 @@ socks_read_cb(struct bufferevent *bev, void *arg)
conn_t *conn = arg;
//struct bufferevent *other;
enum socks_ret socks_ret;
- obfs_assert(bev == conn->input); /* socks must be on the initial bufferevent */
-
+ obfs_assert(bev == conn->input); /* socks only makes sense on the input side */
do {
enum socks_status_t status = socks_state_get_status(conn->socks_state);
@@ -453,7 +456,10 @@ socks_read_cb(struct bufferevent *bev, void *arg)
-1,
BEV_OPT_CLOSE_ON_FREE);
- /* queue handshake, if any, before connecting */
+ bufferevent_setcb(conn->output, obfuscated_read_cb, NULL,
+ socks_event_cb, conn);
+
+ /* Queue handshake, if any, before connecting. */
if (proto_handshake(conn->proto,
bufferevent_get_output(conn->output))<0) {
/* XXXX send socks reply */
@@ -484,7 +490,7 @@ socks_read_cb(struct bufferevent *bev, void *arg)
if (socks_ret == SOCKS_INCOMPLETE)
return; /* need to read more data. */
else if (socks_ret == SOCKS_BROKEN)
- close_conn(conn); /* XXXX maybe send socks reply */
+ close_conn(conn); /* XXXX send socks reply */
else if (socks_ret == SOCKS_CMD_NOT_CONNECT) {
bufferevent_enable(bev, EV_WRITE);
bufferevent_disable(bev, EV_READ);
@@ -567,101 +573,115 @@ error_or_eof(conn_t *conn,
}
/**
- We land in here when an event happens on conn->input.
-*/
+ Called when an "event" happens on conn->input.
+ On the input side, all such events are error conditions.
+ */
static void
input_event_cb(struct bufferevent *bev, short what, void *arg)
{
conn_t *conn = arg;
obfs_assert(bev == conn->input);
- if (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR)) {
- log_warn("Got error: %s",
+ /* It should be impossible to get BEV_EVENT_CONNECTED on this side. */
+ obfs_assert(what & (BEV_EVENT_EOF|BEV_EVENT_ERROR|BEV_EVENT_TIMEOUT));
+ obfs_assert(!(what & BEV_EVENT_CONNECTED));
+
+ log_warn("Got error: %s",
evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()));
- error_or_eof(conn, bev, conn->output);
- }
- /* XXX we don't expect any other events */
+ error_or_eof(conn, bev, conn->output);
}
/**
- We land in here when an event happens on conn->output.
-*/
+ Called when an "event" happens on conn->output.
+ In addition to the error cases dealt with above, this side can see
+ BEV_EVENT_CONNECTED which indicates that the output connection is
+ now open.
+ */
static void
output_event_cb(struct bufferevent *bev, short what, void *arg)
{
conn_t *conn = arg;
obfs_assert(bev == conn->output);
- /**
- If we got the BEV_EVENT_ERROR flag *AND* we are in socks mode
- *AND* we are in the ST_HAVE_ADDR state, chances are that we
- failed connecting to the host requested by the CONNECT call. This
- means that we should send a negative SOCKS reply back to the
- client and terminate the connection.
- */
- if (what & BEV_EVENT_ERROR) {
- if ((conn->mode == LSN_SOCKS_CLIENT) &&
- (conn->socks_state) &&
- (socks_state_get_status(conn->socks_state) == ST_HAVE_ADDR)) {
- log_debug("Connection failed") ;
- /* Enable EV_WRITE so that we can send the response.
- Disable EV_READ so that we don't get more stuff from the client. */
- bufferevent_enable(conn->input, EV_WRITE);
- bufferevent_disable(conn->input, EV_READ);
- socks_send_reply(conn->socks_state, bufferevent_get_output(conn->input),
- evutil_socket_geterror(bufferevent_getfd(bev)));
- bufferevent_setcb(conn->input, NULL,
- close_conn_on_flush, output_event_cb, conn);
- return;
- }
- }
-
- /**
- If the connection is terminating *OR* if we got a BEV_EVENT_ERROR
- but we don't match the case above, we most probably have to close
- this connection soon.
- */
- if (conn->flushing || (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR))) {
+ /* If the connection is terminating *OR* if we got one of the error
+ events, close this connection soon. */
+ if (conn->flushing ||
+ (what & (BEV_EVENT_EOF|BEV_EVENT_ERROR|BEV_EVENT_TIMEOUT))) {
log_warn("Got error: %s",
- evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()));
+ evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()));
error_or_eof(conn, bev, conn->input);
return;
}
- /**
- If we got the BEV_EVENT_CONNECTED flag it means that a connection
- request was succesfull and normally that should have been off a
- CONNECT request by the SOCKS client. If that's the case we should
- send a happy response to the client and switch to start serving
- our pluggable transport protocol.
- */
+ /* Upon successful connection, go ahead and enable traffic on the
+ input side. */
if (what & BEV_EVENT_CONNECTED) {
- /* woo, we're connected. Now the input buffer can start reading. */
conn->is_open = 1;
log_debug("Connection done") ;
bufferevent_enable(conn->input, EV_READ|EV_WRITE);
- if (conn->mode == LSN_SOCKS_CLIENT) {
- struct sockaddr_storage ss;
- struct sockaddr *sa = (struct sockaddr*)&ss;
- socklen_t slen = sizeof(&ss);
- obfs_assert(conn->socks_state);
- if (getpeername(bufferevent_getfd(bev), sa, &slen) == 0) {
- /* Figure out where we actually connected to so that we can tell the
- * socks client */
- socks_state_set_address(conn->socks_state, sa);
- }
- socks_send_reply(conn->socks_state,
- bufferevent_get_output(conn->input), 0);
- /* we sent a socks reply. We can finally move over to being a regular
- input bufferevent. */
- socks_state_free(conn->socks_state);
- conn->socks_state = NULL;
- bufferevent_setcb(conn->input,
- plaintext_read_cb, NULL, input_event_cb, conn);
- if (evbuffer_get_length(bufferevent_get_input(conn->input)) != 0)
- obfuscated_read_cb(bev, conn->input);
- }
return;
}
- /* XXX we don't expect any other events */
+
+ /* unrecognized event */
+ obfs_abort();
+}
+
+/**
+ Called when an "event" happens on conn->output in socks mode.
+ Handles the same cases as output_event_cb but must also generate
+ appropriate socks messages back on the input side.
+ */
+static void
+socks_event_cb(struct bufferevent *bev, short what, void *arg)
+{
+ conn_t *conn = arg;
+ obfs_assert(bev == conn->output);
+
+ /* If we got an error while in the ST_HAVE_ADDR state, chances are
+ that we failed connecting to the host requested by the CONNECT
+ call. This means that we should send a negative SOCKS reply back
+ to the client and terminate the connection. */
+ if ((what & BEV_EVENT_ERROR) &&
+ socks_state_get_status(conn->socks_state) == ST_HAVE_ADDR) {
+ log_debug("Connection failed");
+ /* Enable EV_WRITE so that we can send the response.
+ Disable EV_READ so that we don't get more stuff from the client. */
+ bufferevent_enable(conn->input, EV_WRITE);
+ bufferevent_disable(conn->input, EV_READ);
+ socks_send_reply(conn->socks_state, bufferevent_get_output(conn->input),
+ evutil_socket_geterror(bufferevent_getfd(bev)));
+ bufferevent_setcb(conn->input, NULL,
+ close_conn_on_flush, output_event_cb, conn);
+ return;
+ }
+
+ /* Additional work to do for BEV_EVENT_CONNECTED: send a happy
+ response to the client and switch to the actual obfuscated
+ protocol handlers. */
+ if (what & BEV_EVENT_CONNECTED) {
+ struct sockaddr_storage ss;
+ struct sockaddr *sa = (struct sockaddr*)&ss;
+ socklen_t slen = sizeof(&ss);
+ obfs_assert(conn->socks_state);
+ if (getpeername(bufferevent_getfd(bev), sa, &slen) == 0) {
+ /* Figure out where we actually connected to so that we can tell the
+ * socks client */
+ socks_state_set_address(conn->socks_state, sa);
+ }
+ socks_send_reply(conn->socks_state,
+ bufferevent_get_output(conn->input), 0);
+ /* we sent a socks reply. We can finally move over to being a regular
+ input bufferevent. */
+ socks_state_free(conn->socks_state);
+ conn->socks_state = NULL;
+ bufferevent_setcb(conn->input,
+ plaintext_read_cb, NULL, input_event_cb, conn);
+ bufferevent_setcb(conn->output,
+ obfuscated_read_cb, NULL, output_event_cb, conn);
+ if (evbuffer_get_length(bufferevent_get_input(conn->input)) != 0)
+ obfuscated_read_cb(bev, conn->input);
+ }
+
+ /* also do everything that's done on a normal connection */
+ output_event_cb(bev, what, arg);
}
1
0