tor-commits
Threads by month
- ----- 2026 -----
- 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
- 214603 discussions
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
[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