tor-commits
Threads by month
- ----- 2025 -----
- 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
September 2011
- 19 participants
- 865 discussions

[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

[obfsproxy/master] Fix build on Windows. Fix typo in configure.ac.
by nickm@torproject.org 09 Sep '11
by nickm@torproject.org 09 Sep '11
09 Sep '11
commit 02adf0bec5714cbf9df6ac9eee171fbade0fd6a8
Author: Zack Weinberg <zackw(a)panix.com>
Date: Mon Jul 25 15:50:10 2011 -0700
Fix build on Windows. Fix typo in configure.ac.
---
configure.ac | 2 +-
src/util.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/configure.ac b/configure.ac
index fc82507..08d21c3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
AC_PREREQ([2.61])dnl Possibly earlier will do, but this is what I have
-AC_INIT([obsproxy], [0.0])
+AC_INIT([obfsproxy], [0.0])
AC_CONFIG_SRCDIR([src/main.c])
AM_INIT_AUTOMAKE([foreign])
diff --git a/src/util.c b/src/util.c
index 87087c2..8e63944 100644
--- a/src/util.c
+++ b/src/util.c
@@ -186,7 +186,7 @@ resolve_address_port(const char *address, int nodns, int passive,
free(a);
if (ai_res) {
- if (ai_res == EAI_SYSTEM)
+ if (ai_res == EVUTIL_EAI_SYSTEM)
log_warn("Error resolving %s: %s [%s]",
address, evutil_gai_strerror(ai_res), strerror(ai_errno));
else
1
0

[obfsproxy/master] Restructure event callbacks by state, not connection side
by nickm@torproject.org 09 Sep '11
by nickm@torproject.org 09 Sep '11
09 Sep '11
commit 9ebdad11d6bb8ae42c839a918f3b0116db97e5cb
Author: Zack Weinberg <zackw(a)panix.com>
Date: Mon Jul 25 12:59:06 2011 -0700
Restructure event callbacks by state, not connection side
---
src/network.c | 173 +++++++++++++++++++++++++++++++++------------------------
1 files changed, 101 insertions(+), 72 deletions(-)
diff --git a/src/network.c b/src/network.c
index 31a7013..f3d09cf 100644
--- a/src/network.c
+++ b/src/network.c
@@ -18,6 +18,7 @@
#include <event2/buffer.h>
#include <event2/bufferevent.h>
+#include <event2/bufferevent_struct.h>
#include <event2/listener.h>
#include <event2/util.h>
@@ -56,9 +57,10 @@ 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);
-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);
+static void error_cb(struct bufferevent *bev, short what, void *arg);
+static void flush_error_cb(struct bufferevent *bev, short what, void *arg);
+static void pending_conn_cb(struct bufferevent *bev, short what, void *arg);
+static void pending_socks_cb(struct bufferevent *bev, short what, void *arg);
/**
Puts obfsproxy's networking subsystem on "closing time" mode. This
@@ -213,12 +215,12 @@ simple_client_listener_cb(struct evconnlistener *evcl,
if (!conn->output)
goto err;
- bufferevent_setcb(conn->input, upstream_read_cb, NULL, input_event_cb, conn);
+ 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,
- downstream_read_cb, NULL, output_event_cb, conn);
+ 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)
@@ -282,7 +284,7 @@ socks_client_listener_cb(struct evconnlistener *evcl,
goto err;
fd = -1; /* prevent double-close */
- bufferevent_setcb(conn->input, socks_read_cb, NULL, input_event_cb, conn);
+ bufferevent_setcb(conn->input, socks_read_cb, NULL, error_cb, conn);
bufferevent_enable(conn->input, EV_READ|EV_WRITE);
/* Do not create an output bufferevent at this time; the socks
@@ -335,7 +337,7 @@ simple_server_listener_cb(struct evconnlistener *evcl,
goto err;
fd = -1; /* prevent double-close */
- bufferevent_setcb(conn->input, downstream_read_cb, NULL, input_event_cb, conn);
+ bufferevent_setcb(conn->input, 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 */
@@ -346,7 +348,7 @@ simple_server_listener_cb(struct evconnlistener *evcl,
goto err;
bufferevent_setcb(conn->output, upstream_read_cb, NULL,
- output_event_cb, conn);
+ pending_conn_cb, conn);
/* Queue handshake, if any, before connecting. */
if (proto_handshake(conn->proto,
@@ -457,7 +459,7 @@ socks_read_cb(struct bufferevent *bev, void *arg)
BEV_OPT_CLOSE_ON_FREE);
bufferevent_setcb(conn->output, downstream_read_cb, NULL,
- socks_event_cb, conn);
+ pending_socks_cb, conn);
/* Queue handshake, if any, before connecting. */
if (proto_handshake(conn->proto,
@@ -497,7 +499,7 @@ socks_read_cb(struct bufferevent *bev, void *arg)
socks5_send_reply(bufferevent_get_output(bev), conn->socks_state,
SOCKS5_FAILED_UNSUPPORTED);
bufferevent_setcb(bev, NULL,
- close_conn_on_flush, output_event_cb, conn);
+ close_conn_on_flush, flush_error_cb, conn);
return;
}
}
@@ -552,13 +554,17 @@ 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, struct bufferevent *bev_flush)
+error_or_eof(conn_t *conn, struct bufferevent *bev_err)
{
- log_debug("error_or_eof");
+ struct bufferevent *bev_flush;
+
+ if (bev_err == conn->input) bev_flush = conn->output;
+ else if (bev_err == conn->output) bev_flush = conn->input;
+ else obfs_abort();
- if (conn->flushing || ! conn->is_open ||
- 0 == evbuffer_get_length(bufferevent_get_output(bev_flush))) {
+ log_debug("error_or_eof");
+ if (conn->flushing || !conn->is_open ||
+ evbuffer_get_length(bufferevent_get_output(bev_flush)) == 0) {
close_conn(conn);
return;
}
@@ -567,93 +573,111 @@ error_or_eof(conn_t *conn,
/* Stop reading and writing; wait for the other side to flush if it has
* data. */
bufferevent_disable(bev_err, EV_READ|EV_WRITE);
- bufferevent_disable(bev_flush, EV_READ);
+ bufferevent_setcb(bev_err, NULL, NULL, flush_error_cb, conn);
+ bufferevent_disable(bev_flush, EV_READ);
bufferevent_setcb(bev_flush, NULL,
- close_conn_on_flush, output_event_cb, conn);
+ close_conn_on_flush, flush_error_cb, conn);
bufferevent_enable(bev_flush, EV_WRITE);
}
/**
- Called when an "event" happens on conn->input.
- On the input side, all such events are error conditions.
- */
+ Called when an "event" happens on an already-connected socket.
+ This can only be an error or EOF.
+*/
static void
-input_event_cb(struct bufferevent *bev, short what, void *arg)
+error_cb(struct bufferevent *bev, short what, void *arg)
{
- conn_t *conn = arg;
- obfs_assert(bev == conn->input);
-
- /* It should be impossible to get BEV_EVENT_CONNECTED on this side. */
+ /* It should be impossible to get here with BEV_EVENT_CONNECTED. */
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);
+ error_or_eof(arg, bev);
}
/**
- 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.
- */
+ Called when an event happens on a socket that's in the process of
+ being flushed and closed. As above, this can only be an error.
+*/
static void
-output_event_cb(struct bufferevent *bev, short what, void *arg)
+flush_error_cb(struct bufferevent *bev, short what, void *arg)
{
conn_t *conn = arg;
- obfs_assert(bev == conn->output);
- /* 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()));
- error_or_eof(conn, bev, conn->input);
- return;
- }
+ /* It should be impossible to get here with BEV_EVENT_CONNECTED. */
+ obfs_assert(what & (BEV_EVENT_EOF|BEV_EVENT_ERROR|BEV_EVENT_TIMEOUT));
+ obfs_assert(!(what & BEV_EVENT_CONNECTED));
+
+ obfs_assert(conn->flushing);
+
+ log_warn("Error during flush: %s",
+ evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()));
+ close_conn(conn);
+ return;
+}
- /* Upon successful connection, go ahead and enable traffic on the
- input side. */
+/**
+ 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.
+*/
+static void
+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;
+ else obfs_abort();
+
+ /* Upon successful connection, enable traffic on the other side,
+ and replace this callback with the regular error_cb */
if (what & BEV_EVENT_CONNECTED) {
+ obfs_assert(!conn->flushing);
+
conn->is_open = 1;
- log_debug("Connection done") ;
- bufferevent_enable(conn->input, EV_READ|EV_WRITE);
+ log_debug("Connection successful") ;
+ bufferevent_enable(other, EV_READ|EV_WRITE);
+
+ /* 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);
return;
}
- /* unrecognized event */
- obfs_abort();
+ /* Otherwise, must be an error */
+ error_cb(bev, what, arg);
}
/**
- 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.
+ 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.
*/
static void
-socks_event_cb(struct bufferevent *bev, short what, void *arg)
+pending_socks_cb(struct bufferevent *bev, short what, void *arg)
{
conn_t *conn = arg;
obfs_assert(bev == conn->output);
+ obfs_assert(conn->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
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);
+ 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->input),
+ err);
+ }
+ error_or_eof(conn, bev);
return;
}
@@ -664,7 +688,9 @@ socks_event_cb(struct bufferevent *bev, short what, void *arg)
struct sockaddr_storage ss;
struct sockaddr *sa = (struct sockaddr*)&ss;
socklen_t slen = sizeof(&ss);
- obfs_assert(conn->socks_state);
+
+ obfs_assert(!conn->flushing);
+
if (getpeername(bufferevent_getfd(bev), sa, &slen) == 0) {
/* Figure out where we actually connected to so that we can tell the
* socks client */
@@ -672,18 +698,21 @@ socks_event_cb(struct bufferevent *bev, short what, void *arg)
}
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. */
+
+ /* Switch to regular upstream behavior. */
socks_state_free(conn->socks_state);
conn->socks_state = NULL;
- bufferevent_setcb(conn->input,
- upstream_read_cb, NULL, input_event_cb, conn);
- bufferevent_setcb(conn->output,
- downstream_read_cb, NULL, output_event_cb, conn);
+ 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);
+ return;
}
- /* also do everything that's done on a normal connection */
- output_event_cb(bev, what, arg);
+ /* unknown event code */
+ obfs_abort();
}
1
0

[obfsproxy/master] Fix some copy-and-paste errors in network.c and some resource-reuse errors in tester.py.in
by nickm@torproject.org 09 Sep '11
by nickm@torproject.org 09 Sep '11
09 Sep '11
commit 3d5e463cb108e31b9c575cbfbe1917a92ef5c0f7
Author: Zack Weinberg <zackw(a)panix.com>
Date: Wed Jul 27 10:51:13 2011 -0700
Fix some copy-and-paste errors in network.c and some resource-reuse errors in tester.py.in
---
src/network.c | 11 ++++++++---
src/test/tester.py.in | 45 ++++++++++++++++++++++++++++++---------------
2 files changed, 38 insertions(+), 18 deletions(-)
diff --git a/src/network.c b/src/network.c
index f7a94d3..f05c5b8 100644
--- a/src/network.c
+++ b/src/network.c
@@ -409,8 +409,8 @@ conn_free(conn_t *conn)
socks_state_free(conn->socks_state);
if (conn->upstream)
bufferevent_free(conn->upstream);
- if (conn->upstream)
- bufferevent_free(conn->upstream);
+ if (conn->downstream)
+ bufferevent_free(conn->downstream);
memset(conn, 0x99, sizeof(conn_t));
free(conn);
@@ -611,6 +611,11 @@ error_cb(struct bufferevent *bev, short what, void *arg)
obfs_assert(what & (BEV_EVENT_EOF|BEV_EVENT_ERROR|BEV_EVENT_TIMEOUT));
obfs_assert(!(what & BEV_EVENT_CONNECTED));
+ /* If we get EAGAIN or EINPROGRESS here, something has gone horribly
+ wrong. */
+ obfs_assert(EVUTIL_SOCKET_ERROR() != EAGAIN &&
+ EVUTIL_SOCKET_ERROR() != EINPROGRESS);
+
log_warn("Got error: %s",
evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()));
error_or_eof(arg, bev);
@@ -731,7 +736,7 @@ pending_socks_cb(struct bufferevent *bev, short what, void *arg)
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);
+ upstream_read_cb(conn->upstream, conn);
return;
}
diff --git a/src/test/tester.py.in b/src/test/tester.py.in
index b0602ed..104026c 100644
--- a/src/test/tester.py.in
+++ b/src/test/tester.py.in
@@ -147,9 +147,6 @@ class SocksTest(object):
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
- self.input_chan = connect_with_retry(("127.0.0.1", ENTRY_PORT))
- self.input_chan.settimeout(1.0)
-
def tearDown(self):
if self.obfs_server.returncode is None:
self.obfs_server.terminate()
@@ -193,14 +190,17 @@ class SocksTest(object):
def socksTest(self, sequence):
sending = True
good = True
+ input_chan = connect_with_retry(("127.0.0.1", ENTRY_PORT))
+ input_chan.settimeout(1.0)
+
for msg in sequence:
if msg is False:
- self.input_chan.shutdown(socket.SHUT_WR)
+ input_chan.shutdown(socket.SHUT_WR)
# Expect either a clean closedown or a connection reset
# at this point.
got = ""
try:
- got = self.input_chan.recv(4096)
+ got = input_chan.recv(4096)
except socket.error, e:
if e.errno != errno.ECONNRESET: raise
self.assertEqual(got, "")
@@ -213,33 +213,36 @@ class SocksTest(object):
else:
raise TypeError("incomprehensible msg: " + repr(msg))
if sending:
- self.input_chan.sendall(exp)
+ input_chan.sendall(exp)
else:
got = ""
try:
- got = self.input_chan.recv(4096)
+ got = input_chan.recv(4096)
except socket.error, e:
if e.errno != errno.ECONNRESET: raise
self.assertEqual(got, exp)
if good:
- self.input_chan.sendall(TEST_FILE)
- self.input_chan.shutdown(socket.SHUT_WR)
+ input_chan.sendall(TEST_FILE)
+ input_chan.shutdown(socket.SHUT_WR)
try:
output = self.output_reader.get()
except Queue.Empty:
output = ""
- self.assertEqual(output, TEST_FILE)
- self.input_chan.close()
+ input_chan.close()
self.checkSubprocesses()
+ if good:
+ self.assertEqual(output, TEST_FILE)
+
+
def test_illformed(self):
# ill-formed socks message - server should drop connection
self.socksTest([ "GET / HTTP/1.1\r\nHost: 127.0.0.1\r\n"
"Connection: close\r\n\r\n",
False ])
- def test_socks4_unsupported_methods(self):
+ def test_socks4_unsupported_method_1(self):
# SOCKS4 bind request - should fail, presently just drops connection
self.socksTest([ ( (4, 2, SERVER_PORT, 127, 0, 0, 1, 0), "!BBH5B" ),
False ])
@@ -249,23 +252,35 @@ class SocksTest(object):
self.socksTest([ ( (4, 1, SERVER_PORT, 127, 0, 0, 1, 0), "!BBH5B" ),
( (0, 90, SERVER_PORT, 127, 0, 0, 1), "!BBH4B" ) ])
- def test_socks5_bad_handshakes(self):
+ def test_socks5_bad_handshake_1(self):
self.socksTest([ "\x05", False ])
+
+ def test_socks5_bad_handshake_2(self):
self.socksTest([ "\x05\x00", False ])
+
+ def test_socks5_bad_handshake_3(self):
self.socksTest([ "\x05\x01\x01", "\x05\xFF", False ])
+
+ def test_socks5_bad_handshake_4(self):
self.socksTest([ "\x05\x01\x080", "\x05\xFF", False ])
+
+ def test_socks5_bad_handshake_5(self):
self.socksTest([ "\x05\x02\x01\x02", "\x05\xFF", False ])
- def test_socks5_bad_requests(self):
+ def test_socks5_bad_request_1(self):
self.socksTest([ "\x05\x01\x00", "\x05\x00", "\x05\x00",
"\x05\x07\x00", False ])
+
+ def test_socks5_bad_request_2(self):
self.socksTest([ "\x05\x02\x00\x01", "\x05\x00", "\x05\x00",
"\x05\x07\x00", False ])
- def test_socks5_unsupported_methods(self):
+ def test_socks5_unsupported_method_1(self):
self.socksTest([ "\x05\x01\x00", "\x05\x00",
( (5, 2, 0, 1, 127, 0, 0, 1, SERVER_PORT), "!8BH" ),
"\x05\x07\x00", False ])
+
+ def test_socks5_unsupported_method_2(self):
self.socksTest([ "\x05\x01\x00", "\x05\x00",
( (5, 3, 0, 1, 127, 0, 0, 1, SERVER_PORT), "!8BH" ),
"\x05\x07\x00", False ])
1
0

[obfsproxy/master] Add a whole bunch more logging and test framework tracking. Properly distinguish BEV_EVENT_EOF from BEV_EVENT_ERROR in error_cb (flush_error_cb and pending_socks_cb are still sloppy).
by nickm@torproject.org 09 Sep '11
by nickm@torproject.org 09 Sep '11
09 Sep '11
commit dfdc4fb57b2633359d41a993d78bc3ae8f7b92fc
Author: Zack Weinberg <zackw(a)panix.com>
Date: Wed Jul 27 17:06:41 2011 -0700
Add a whole bunch more logging and test framework tracking. Properly distinguish BEV_EVENT_EOF from BEV_EVENT_ERROR in error_cb (flush_error_cb and pending_socks_cb are still sloppy).
---
src/main.c | 1 +
src/network.c | 91 +++++++++++++++++++------
src/network.h | 2 +
src/test/tester.py.in | 183 ++++++++++++++++++++++++++++--------------------
src/util.c | 41 +++++++++++
src/util.h | 4 +
6 files changed, 226 insertions(+), 96 deletions(-)
diff --git a/src/main.c b/src/main.c
index f6280c2..1459af3 100644
--- a/src/main.c
+++ b/src/main.c
@@ -91,6 +91,7 @@ handle_signal_cb(evutil_socket_t fd, short what, void *arg)
void
finish_shutdown(void)
{
+ log_debug("Finishing shutdown.");
event_base_loopexit(the_event_base, NULL);
}
diff --git a/src/network.c b/src/network.c
index f05c5b8..7831a4e 100644
--- a/src/network.c
+++ b/src/network.c
@@ -92,6 +92,8 @@ static void pending_socks_cb(struct bufferevent *bev, short what, void *arg);
void
start_shutdown(int barbaric)
{
+ log_debug("Beginning %s shutdown.", barbaric ? "barbaric" : "normal");
+
if (!shutting_down)
shutting_down=1;
@@ -115,6 +117,7 @@ close_all_connections(void)
{
if (!connections)
return;
+ log_debug("Closing all connections.");
SMARTLIST_FOREACH(connections, conn_t *, conn,
{ conn_free(conn); });
smartlist_free(connections);
@@ -143,6 +146,8 @@ create_listener(struct event_base *base, protocol_params_t *params)
default: obfs_abort();
}
+ lsn->address = printable_address(params->listen_addr->ai_addr,
+ params->listen_addr->ai_addrlen);
lsn->proto_params = params;
lsn->listener =
evconnlistener_new_bind(base, callback, lsn, flags, -1,
@@ -156,6 +161,9 @@ create_listener(struct event_base *base, protocol_params_t *params)
return 0;
}
+ log_debug("Now listening on %s in mode %d, protocol %s.",
+ lsn->address, params->mode, params->vtable->name);
+
/* If we don't have a listener list, create one now. */
if (!listeners)
listeners = smartlist_create();
@@ -170,6 +178,8 @@ create_listener(struct event_base *base, protocol_params_t *params)
static void
listener_free(listener_t *lsn)
{
+ if (lsn->address)
+ free(lsn->address);
if (lsn->listener)
evconnlistener_free(lsn->listener);
if (lsn->proto_params)
@@ -206,7 +216,9 @@ simple_client_listener_cb(struct evconnlistener *evcl,
struct event_base *base;
conn_t *conn = xzalloc(sizeof(conn_t));
- log_debug("%s: connection attempt.", __func__);
+ conn->peername = printable_address(sourceaddr, socklen);
+ log_debug("%s: connection to %s from %s", __func__,
+ lsn->address, conn->peername);
conn->mode = lsn->proto_params->mode;
obfs_assert(conn->mode == LSN_SIMPLE_CLIENT);
@@ -280,7 +292,9 @@ socks_client_listener_cb(struct evconnlistener *evcl,
struct event_base *base;
conn_t *conn = xzalloc(sizeof(conn_t));
- log_debug("%s: connection attempt.", __func__);
+ conn->peername = printable_address(sourceaddr, socklen);
+ log_debug("%s: connection to %s from %s", __func__,
+ lsn->address, conn->peername);
conn->mode = lsn->proto_params->mode;
obfs_assert(conn->mode == LSN_SOCKS_CLIENT);
@@ -336,7 +350,9 @@ simple_server_listener_cb(struct evconnlistener *evcl,
struct event_base *base;
conn_t *conn = xzalloc(sizeof(conn_t));
- log_debug("%s: connection attempt.", __func__);
+ conn->peername = printable_address(sourceaddr, socklen);
+ log_debug("%s: connection to %s from %s", __func__,
+ lsn->address, conn->peername);
conn->mode = lsn->proto_params->mode;
obfs_assert(conn->mode == LSN_SIMPLE_SERVER);
@@ -403,6 +419,8 @@ simple_server_listener_cb(struct evconnlistener *evcl,
static void
conn_free(conn_t *conn)
{
+ if (conn->peername)
+ free(conn->peername);
if (conn->proto)
proto_destroy(conn->proto);
if (conn->socks_state)
@@ -423,10 +441,11 @@ 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);
- 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. */
@@ -447,6 +466,7 @@ static void
close_conn_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);
@@ -460,6 +480,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);
@@ -534,9 +555,9 @@ static void
upstream_read_cb(struct bufferevent *bev, void *arg)
{
conn_t *conn = arg;
+ log_debug("%s for %s", __func__, conn->peername);
obfs_assert(bev == conn->upstream);
- log_debug("Got data on upstream side");
if (proto_send(conn->proto,
bufferevent_get_input(conn->upstream),
bufferevent_get_output(conn->downstream)) < 0)
@@ -553,9 +574,9 @@ downstream_read_cb(struct bufferevent *bev, void *arg)
{
conn_t *conn = arg;
enum recv_ret r;
+ log_debug("%s for %s", __func__, conn->peername);
obfs_assert(bev == conn->downstream);
- log_debug("Got data on downstream side");
r = proto_recv(conn->proto,
bufferevent_get_input(conn->downstream),
bufferevent_get_output(conn->upstream));
@@ -576,12 +597,12 @@ static void
error_or_eof(conn_t *conn, struct bufferevent *bev_err)
{
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("error_or_eof");
if (conn->flushing || !conn->is_open ||
evbuffer_get_length(bufferevent_get_output(bev_flush)) == 0) {
close_conn(conn);
@@ -607,17 +628,35 @@ error_or_eof(conn_t *conn, struct bufferevent *bev_err)
static void
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,
+ what, errcode);
+
/* It should be impossible to get here with BEV_EVENT_CONNECTED. */
obfs_assert(what & (BEV_EVENT_EOF|BEV_EVENT_ERROR|BEV_EVENT_TIMEOUT));
obfs_assert(!(what & BEV_EVENT_CONNECTED));
- /* If we get EAGAIN or EINPROGRESS here, something has gone horribly
- wrong. */
- obfs_assert(EVUTIL_SOCKET_ERROR() != EAGAIN &&
- EVUTIL_SOCKET_ERROR() != EINPROGRESS);
-
- log_warn("Got error: %s",
- evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()));
+ if (what & BEV_EVENT_ERROR) {
+ /* If we get EAGAIN, EINTR, or EINPROGRESS here, something has
+ gone horribly wrong. */
+ obfs_assert(errcode != EAGAIN && errcode != EINTR &&
+ errcode != EINPROGRESS);
+
+ log_warn("Error on %s side of connection from %s: %s",
+ bev == conn->upstream ? "upstream" : "downstream",
+ 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);
+ } else {
+ obfs_assert(what & BEV_EVENT_TIMEOUT);
+ log_info("Timeout on %s side of connection from %s",
+ bev == conn->upstream ? "upstream" : "downstream",
+ conn->peername);
+ }
error_or_eof(arg, bev);
}
@@ -629,6 +668,9 @@ static void
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,
+ what, errcode);
/* It should be impossible to get here with BEV_EVENT_CONNECTED. */
obfs_assert(what & (BEV_EVENT_EOF|BEV_EVENT_ERROR|BEV_EVENT_TIMEOUT));
@@ -636,8 +678,10 @@ flush_error_cb(struct bufferevent *bev, short what, void *arg)
obfs_assert(conn->flushing);
- log_warn("Error during flush: %s",
- evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()));
+ log_warn("Error during flush of %s side of connection from %s: %s",
+ bev == conn->upstream ? "upstream" : "downstream",
+ conn->peername,
+ evutil_socket_error_to_string(errcode));
close_conn(conn);
return;
}
@@ -653,6 +697,8 @@ pending_conn_cb(struct bufferevent *bev, short what, void *arg)
{
conn_t *conn = arg;
struct bufferevent *other;
+ log_debug("%s for %s", __func__, conn->peername);
+
if (bev == conn->upstream) other = conn->downstream;
else if (bev == conn->downstream) other = conn->upstream;
else obfs_abort();
@@ -663,13 +709,15 @@ pending_conn_cb(struct bufferevent *bev, short what, void *arg)
obfs_assert(!conn->flushing);
conn->is_open = 1;
- log_debug("Connection successful");
- bufferevent_enable(other, EV_READ|EV_WRITE);
+ log_debug("Successful %s connection for %s",
+ bev == conn->upstream ? "upstream" : "downstream",
+ conn->peername);
/* 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);
return;
}
@@ -686,13 +734,16 @@ static void
pending_socks_cb(struct bufferevent *bev, short what, void *arg)
{
conn_t *conn = arg;
+ log_debug("%s for %s", __func__, conn->peername);
obfs_assert(bev == conn->downstream);
obfs_assert(conn->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
call. This means that we should send a negative SOCKS reply back
- to the client and terminate the connection. */
+ to the client and terminate the connection.
+ XXX properly distinguish BEV_EVENT_EOF from BEV_EVENT_ERROR;
+ 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",
diff --git a/src/network.h b/src/network.h
index c5ef69e..4ae96fc 100644
--- a/src/network.h
+++ b/src/network.h
@@ -14,11 +14,13 @@ void start_shutdown(int barbaric);
#ifdef NETWORK_PRIVATE
typedef struct listener_t {
+ char *address;
protocol_params_t *proto_params;
struct evconnlistener *listener;
} listener_t;
typedef struct conn_t {
+ char *peername;
protocol_t *proto;
socks_state_t *socks_state;
struct bufferevent *upstream;
diff --git a/src/test/tester.py.in b/src/test/tester.py.in
index 104026c..d9040fe 100644
--- a/src/test/tester.py.in
+++ b/src/test/tester.py.in
@@ -7,16 +7,86 @@
# You need to be able to make connections to arbitrary high-numbered
# TCP ports on the loopback interface.
+import difflib
import errno
import multiprocessing
import Queue
+import re
import signal
import socket
import struct
import subprocess
import time
+import traceback
import unittest
+# Helper: generate unified-format diffs between two named strings.
+# Pythonic escaped-string syntax is used for unprintable characters.
+
+def diff(label, expected, received):
+ if expected == received:
+ return ""
+ else:
+ return (label + "\n"
+ + "\n".join(s.encode("string_escape")
+ for s in
+ difflib.unified_diff(expected.split("\n"),
+ received.split("\n"),
+ "expected", "received",
+ lineterm=""))
+ + "\n")
+
+# Helper: Run obfsproxy instances and confirm that they have
+# completed without any errors.
+
+class Obfsproxy(subprocess.Popen):
+ def __init__(self, *args, **kwargs):
+ argv = ["./obfsproxy", "--log-min-severity=debug"]
+ if len(args) == 1 and (isinstance(args[0], list) or
+ isinstance(args[0], tuple)):
+ argv.extend(args[0])
+ else:
+ argv.extend(args)
+
+ subprocess.Popen.__init__(self, argv,
+ stdin=open("/dev/null", "r"),
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ **kwargs)
+
+ severe_error_re = re.compile(r"\[(?:warn|err(?:or)?)\]")
+
+ def check_completion(self, label):
+ if self.poll() is None:
+ self.send_signal(signal.SIGINT)
+
+ (out, err) = self.communicate()
+
+ report = ""
+ def indent(s):
+ return "| " + "\n| ".join(s.strip().split("\n"))
+
+ # exit status should be zero
+ if self.returncode > 0:
+ report += label + " exit code: %d\n" % self.returncode
+ elif self.returncode < 0:
+ report += label + " killed: signal %d\n" % -self.returncode
+
+ # there should be nothing on stdout
+ if out != "":
+ report += label + " stdout:\n%s\n" % indent(out)
+
+ # there will be debugging messages on stderr, but there should be
+ # no [warn], [err], or [error] messages.
+ if self.severe_error_re.search(err):
+ report += label + " stderr:\n%s\n" % indent(err)
+
+ return report
+
+ def stop(self):
+ if self.poll() is None:
+ self.terminate()
+
# Helper: Repeatedly try to connect to the specified server socket
# until either it succeeds or one full second has elapsed. (Surely
# there is a better way to do this?)
@@ -89,32 +159,14 @@ EXIT_PORT = 5001
class DirectTest(object):
def setUp(self):
self.output_reader = ReadWorker(("127.0.0.1", EXIT_PORT))
- self.obfs = subprocess.Popen(
- self.obfs_args,
- stdin=open("/dev/null", "r"),
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
-
+ self.obfs = Obfsproxy(self.obfs_args)
self.input_chan = connect_with_retry(("127.0.0.1", ENTRY_PORT))
self.input_chan.settimeout(1.0)
def tearDown(self):
- if self.obfs.returncode is None:
- self.obfs.terminate()
+ self.obfs.stop()
self.output_reader.stop()
-
- def checkSubprocesses(self):
- if self.obfs.poll() is None:
- self.obfs.send_signal(signal.SIGINT)
-
- (out, err) = self.obfs.communicate()
-
- if (out != "" or err != "" or self.obfs.returncode != 0):
- self.fail("obfsproxy process failure:\n"
- "\treturn code: %d\n"
- "\tstdout: %s\n"
- "\tstderr: %s\n"
- % (self.obfs.returncode, out, err))
+ self.input_chan.close()
def test_direct_transfer(self):
# Open a server and a simple client (in the same process) and
@@ -127,8 +179,11 @@ class DirectTest(object):
except Queue.Empty:
output = ""
- self.checkSubprocesses()
- self.assertEqual(output, TEST_FILE)
+ report = self.obfs.check_completion("obfsproxy")
+ report += diff("errors in transfer:", TEST_FILE, output)
+
+ if report != "":
+ self.fail("\n" + report)
# Same as above, but we use a socks client instead of a simple client,
# and the server's a separate process.
@@ -136,47 +191,14 @@ class DirectTest(object):
class SocksTest(object):
def setUp(self):
self.output_reader = ReadWorker(("127.0.0.1", EXIT_PORT))
- self.obfs_server = subprocess.Popen(
- self.server_args,
- stdin=open("/dev/null", "r"),
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- self.obfs_client = subprocess.Popen(
- self.client_args,
- stdin=open("/dev/null", "r"),
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
+ self.obfs_server = Obfsproxy(self.server_args)
+ self.obfs_client = Obfsproxy(self.client_args)
def tearDown(self):
- if self.obfs_server.returncode is None:
- self.obfs_server.terminate()
- if self.obfs_client.returncode is None:
- self.obfs_client.terminate()
+ self.obfs_server.stop()
+ self.obfs_client.stop()
self.output_reader.stop()
- def checkSubprocesses(self):
- if self.obfs_server.poll() is None:
- self.obfs_server.send_signal(signal.SIGINT)
- if self.obfs_client.poll() is None:
- self.obfs_client.send_signal(signal.SIGINT)
-
- (sout, serr) = self.obfs_server.communicate()
- (cout, cerr) = self.obfs_client.communicate()
-
- if (sout != "" or serr != "" or cout != "" or cerr != ""
- or self.obfs_server.returncode != 0
- or self.obfs_client.returncode != 0):
- self.fail("obfsproxy process failures:\n"
- "\tclient return code: %d\n"
- "\tserver return code: %d\n"
- "\tclient stdout: %s\n"
- "\tclient stderr: %s\n"
- "\tserver stdout: %s\n"
- "\tserver stderr: %s\n"
- % (self.obfs_client.returncode,
- self.obfs_server.returncode,
- cout, cerr, sout, serr))
-
# 'sequence' is a sequence of SOCKS[45] protocol messages
# which we will send or receive. Sends alternate with
# receives. Each entry may be a string, which is sent or
@@ -187,7 +209,7 @@ class SocksTest(object):
# the SOCKS sequence without the server having dropped the
# connection, we transmit the test file and expect to get it
# back from the far end.
- def socksTest(self, sequence):
+ def socksTestInner(self, sequence):
sending = True
good = True
input_chan = connect_with_retry(("127.0.0.1", ENTRY_PORT))
@@ -230,10 +252,25 @@ class SocksTest(object):
output = ""
input_chan.close()
- self.checkSubprocesses()
+ if good: return output
+ else: return None
- if good:
- self.assertEqual(output, TEST_FILE)
+ def socksTest(self, sequence):
+ try:
+ output = self.socksTestInner(sequence)
+ report = ""
+ except Exception:
+ output = None
+ report = traceback.format_exc()
+
+ report += self.obfs_server.check_completion("obfsproxy server")
+ report += self.obfs_client.check_completion("obfsproxy client")
+
+ if output is not None:
+ report += diff("errors in transfer:", TEST_FILE, output)
+
+ if report != "":
+ self.fail("\n" + report)
def test_illformed(self):
@@ -295,8 +332,7 @@ class SocksTest(object):
#
class DirectObfs2(DirectTest, unittest.TestCase):
- obfs_args = ("./obfsproxy", "--log-min-severity=warn",
- "obfs2",
+ obfs_args = ("obfs2",
"--dest=127.0.0.1:%d" % EXIT_PORT,
"server", "127.0.0.1:%d" % SERVER_PORT,
"+", "obfs2",
@@ -304,8 +340,7 @@ class DirectObfs2(DirectTest, unittest.TestCase):
"client", "127.0.0.1:%d" % ENTRY_PORT)
class DirectDummy(DirectTest, unittest.TestCase):
- obfs_args = ("./obfsproxy", "--log-min-severity=warn",
- "dummy", "server",
+ obfs_args = ("dummy", "server",
"127.0.0.1:%d" % SERVER_PORT,
"127.0.0.1:%d" % EXIT_PORT,
"+", "dummy", "client",
@@ -313,21 +348,17 @@ class DirectDummy(DirectTest, unittest.TestCase):
"127.0.0.1:%d" % SERVER_PORT)
class SocksObfs2(SocksTest, unittest.TestCase):
- server_args = ("./obfsproxy", "--log-min-severity=warn",
- "obfs2",
+ server_args = ("obfs2",
"--dest=127.0.0.1:%d" % EXIT_PORT,
"server", "127.0.0.1:%d" % SERVER_PORT)
- client_args = ("./obfsproxy", "--log-min-severity=warn",
- "obfs2",
+ client_args = ("obfs2",
"socks", "127.0.0.1:%d" % ENTRY_PORT)
class SocksDummy(SocksTest, unittest.TestCase):
- server_args = ("./obfsproxy", "--log-min-severity=warn",
- "dummy", "server",
+ server_args = ("dummy", "server",
"127.0.0.1:%d" % SERVER_PORT,
"127.0.0.1:%d" % EXIT_PORT)
- client_args = ("./obfsproxy", "--log-min-severity=warn",
- "dummy", "socks",
+ client_args = ("dummy", "socks",
"127.0.0.1:%d" % ENTRY_PORT)
TEST_FILE = """\
diff --git a/src/util.c b/src/util.c
index e44b131..46d4b42 100644
--- a/src/util.c
+++ b/src/util.c
@@ -10,6 +10,10 @@
#include <unistd.h>
#include <event2/dns.h>
+#include <arpa/inet.h>
+#ifdef AF_LOCAL
+#include <sys/un.h>
+#endif
/** Any size_t larger than this amount is likely to be an underflow. */
#define SIZE_T_CEILING (SIZE_MAX/2 - 16)
@@ -195,6 +199,43 @@ resolve_address_port(const char *address, int nodns, int passive,
return ai;
}
+char *
+printable_address(struct sockaddr *addr, socklen_t addrlen)
+{
+ char abuf[INET6_ADDRSTRLEN];
+ char apbuf[INET6_ADDRSTRLEN + 8]; /* []:65535 is 8 characters */
+
+ switch (addr->sa_family) {
+ case AF_INET: {
+ struct sockaddr_in *sin = (struct sockaddr_in*)addr;
+ if (!inet_ntop(AF_INET, &sin->sin_addr, abuf, INET6_ADDRSTRLEN))
+ break;
+ obfs_snprintf(apbuf, sizeof apbuf, "%s:%d", abuf, ntohs(sin->sin_port));
+ return xstrdup(apbuf);
+ }
+
+ case AF_INET6: {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)addr;
+ if (!inet_ntop(AF_INET, &sin6->sin6_addr, abuf, INET6_ADDRSTRLEN))
+ break;
+ obfs_snprintf(apbuf, sizeof apbuf, "[%s]:%d", abuf,
+ ntohs(sin6->sin6_port));
+ return xstrdup(apbuf);
+ }
+
+#ifdef AF_LOCAL
+ case AF_LOCAL:
+ return xstrdup(((struct sockaddr_un*)addr)->sun_path);
+#endif
+ default:
+ break;
+ }
+
+ obfs_snprintf(apbuf, sizeof apbuf,
+ "<addr family %d>", addr->sa_family);
+ return xstrdup(apbuf);
+}
+
static struct evdns_base *the_evdns_base = NULL;
struct evdns_base *
diff --git a/src/util.h b/src/util.h
index 4fc1a33..5108b62 100644
--- a/src/util.h
+++ b/src/util.h
@@ -93,6 +93,10 @@ struct evutil_addrinfo *resolve_address_port(const char *address,
int nodns, int passive,
const char *default_port);
+/** Produce a printable name for this sockaddr. The result is in
+ malloced memory. */
+char *printable_address(struct sockaddr *addr, socklen_t addrlen);
+
struct evdns_base *get_evdns_base(void);
int init_evdns_base(struct event_base *base);
1
0