commit 67a106ad3bbafe83f1917d8060a1c78bf6d43ff6 Author: George Kadianakis desnacked@gmail.com Date: Sun May 29 04:04:32 2011 +0200
Implements the protocol side of the new CLI. --- src/network.c | 60 ++++++---------------- src/network.h | 14 +++-- src/protocol.c | 29 ++++++----- src/protocol.h | 37 ++++++++------ src/protocols/dummy.c | 70 ++++++++++++++++++++++++- src/protocols/dummy.h | 5 +- src/protocols/obfs2.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++--- src/protocols/obfs2.h | 5 +- src/socks.h | 1 - 9 files changed, 262 insertions(+), 94 deletions(-)
diff --git a/src/network.c b/src/network.c index cfdd398..1c4b853 100644 --- a/src/network.c +++ b/src/network.c @@ -16,20 +16,11 @@ #include <stdlib.h> #include <string.h>
-#include <event2/buffer.h> -#include <event2/bufferevent.h> -#include <event2/listener.h> -#include <event2/event.h> - #include <errno.h> #include <event2/util.h>
struct listener_t { struct evconnlistener *listener; - struct sockaddr_storage target_address; - int target_address_len; - int mode; - int proto; /* Protocol that this listener can speak. */ protocol_params_t *proto_params; };
@@ -49,46 +40,29 @@ static void output_event_cb(struct bufferevent *bev, short what, void *arg);
listener_t * listener_new(struct event_base *base, - int mode, int protocol, - const struct sockaddr *on_address, int on_address_len, - const struct sockaddr *target_address, int target_address_len, - const char *shared_secret, size_t shared_secret_len) + int n_options, char **options) { const unsigned flags = LEV_OPT_CLOSE_ON_FREE|LEV_OPT_CLOSE_ON_EXEC|LEV_OPT_REUSEABLE; - listener_t *lsn = calloc(1, sizeof(listener_t));
- assert(mode == LSN_SIMPLE_CLIENT || mode == LSN_SIMPLE_SERVER || - mode == LSN_SOCKS_CLIENT); - - if (set_up_protocol(protocol)<0) { - printf("This is just terrible. We can't even set up a protocol! Exiting.\n"); - exit(1); - } - - lsn->proto = protocol; - lsn->mode = mode; + listener_t *lsn = calloc(1, sizeof(listener_t)); + if (!lsn) + return NULL;
protocol_params_t *proto_params = calloc(1, sizeof(protocol_params_t)); - proto_params->is_initiator = mode != LSN_SIMPLE_SERVER; - proto_params->shared_secret = shared_secret; - proto_params->shared_secret_len = shared_secret_len; - lsn->proto_params = proto_params; - - if (target_address) { - assert(target_address_len <= sizeof(struct sockaddr_storage)); - memcpy(&lsn->target_address, target_address, target_address_len); - lsn->target_address_len = target_address_len; - } else { - assert(lsn->mode == LSN_SOCKS_CLIENT); + + if (set_up_protocol(n_options,options,lsn->proto_params)<0) { + listener_free(lsn); + return NULL; }
lsn->listener = evconnlistener_new_bind(base, simple_listener_cb, lsn, flags, -1, - on_address, - on_address_len); + &lsn->proto_params->on_address, + lsn->proto_params->on_address_len); + if (!lsn->listener) { listener_free(lsn); return NULL; @@ -101,8 +75,9 @@ static void protocol_params_free(protocol_params_t *params) { assert(params); + if (params->shared_secret) - free(¶ms->shared_secret); + free(params->shared_secret); free(params); }
@@ -129,10 +104,9 @@ simple_listener_cb(struct evconnlistener *evcl,
dbg(("Got a connection\n"));
- conn->mode = lsn->mode; + conn->mode = lsn->proto_params->mode;
- conn->proto = proto_new(lsn->proto, - lsn->proto_params); + conn->proto = proto_new(lsn->proto_params); if (!conn->proto) { printf("Creation of protocol object failed! Closing connection.\n"); goto err; @@ -194,8 +168,8 @@ simple_listener_cb(struct evconnlistener *evcl, if (conn->mode == LSN_SIMPLE_SERVER || conn->mode == LSN_SIMPLE_CLIENT) { /* Launch the connect attempt. */ if (bufferevent_socket_connect(conn->output, - (struct sockaddr *) &lsn->target_address, - lsn->target_address_len)<0) + (struct sockaddr*)&lsn->proto_params->target_address, + lsn->proto_params->target_address_len)<0) goto err;
bufferevent_enable(conn->output, EV_READ|EV_WRITE); diff --git a/src/network.h b/src/network.h index 619e45f..5537680 100644 --- a/src/network.h +++ b/src/network.h @@ -10,6 +10,12 @@
#include <stdlib.h>
+#include <event2/buffer.h> +#include <event2/bufferevent.h> +#include <event2/listener.h> +#include <event2/event.h> + + typedef struct listener_t *listener;
struct sockaddr; @@ -23,12 +29,8 @@ struct socks_state_t; typedef struct listener_t listener_t; struct addrinfo;
-listener_t *listener_new( - struct event_base *base, - int mode, int protocol, - const struct sockaddr *on_address, int on_address_len, - const struct sockaddr *target_address, int target_address_len, - const char *shared_secret, size_t shared_secret_len); +listener_t *listener_new(struct event_base *base, + int n_options, char **options); void listener_free(listener_t *listener);
#ifdef NETWORK_PRIVATE diff --git a/src/protocol.c b/src/protocol.c index 8fff6a3..ce96f86 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -1,6 +1,7 @@ #include <stdlib.h> #include <stdio.h> #include <assert.h> +#include <string.h>
#include "protocol.h" #include "network.h" @@ -13,15 +14,18 @@ It's called once in the runtime of the program for each proto. */ int -set_up_protocol(int protocol) { - if (protocol == OBFS2_PROTOCOL) - obfs2_init(); - else if (protocol == DUMMY_PROTOCOL) - dummy_init(); +set_up_protocol(int n_options, char **options, + struct protocol_params_t *params) +{ + char **name = options; + while (!strncmp(*name,"--",2)) + name++; + if (!strcmp(*name,"dummy")) + return dummy_init(n_options, options, params); + else if (!strcmp(*name,"obfs2")) + return obfs2_init(n_options, options, params); else return -1; - - return 1; }
/** @@ -31,7 +35,7 @@ set_up_protocol(int protocol) { Return the protocol_t if successful, NULL otherwise. */ struct protocol_t * -proto_new(int protocol, protocol_params_t *params) { +proto_new(protocol_params_t *params) { struct protocol_t *proto = calloc(1, sizeof(struct protocol_t)); if (!proto) return NULL; @@ -40,11 +44,9 @@ proto_new(int protocol, protocol_params_t *params) { if (!proto->vtable) return NULL;
- if (protocol == OBFS2_PROTOCOL) { - proto->proto = protocol; + if (params->proto == OBFS2_PROTOCOL) { proto->state = obfs2_new(proto, params); - } else if (protocol == DUMMY_PROTOCOL) { - proto->proto = protocol; + } else if (params->proto == DUMMY_PROTOCOL) { proto->state = dummy_new(proto, NULL); }
@@ -81,7 +83,8 @@ proto_recv(struct protocol_t *proto, void *source, void *dest) { return -1; }
-void proto_destroy(struct protocol_t *proto) { +void +proto_destroy(struct protocol_t *proto) { assert(proto); assert(proto->state);
diff --git a/src/protocol.h b/src/protocol.h index e4c3e0f..646bf7c 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -1,3 +1,5 @@ +#include <event2/buffer.h> + #ifndef PROTOCOL_H #define PROTOCOL_H
@@ -5,6 +7,7 @@ #define OBFS2_PROTOCOL 1
struct evbuffer; +struct listener_t;
/** This struct defines parameters of the protocol per-listener basis. @@ -15,15 +18,17 @@ struct evbuffer; */ typedef struct protocol_params_t { int is_initiator; - - const char *shared_secret; + struct sockaddr_storage target_address; + int target_address_len; + struct sockaddr on_address; + int on_address_len; + int mode; + int proto; /* Protocol that this listener can speak. */ + char *shared_secret; size_t shared_secret_len; } protocol_params_t;
struct protocol_t { - /* protocol */ - int proto; - /* protocol vtable */ struct protocol_vtable *vtable;
@@ -39,17 +44,25 @@ struct protocol_t { */ void *state; }; +int set_up_protocol(int n_options, char **options, + struct protocol_params_t *params); +struct protocol_t *proto_new(struct protocol_params_t *params); +void proto_destroy(struct protocol_t *proto); +int proto_handshake(struct protocol_t *proto, void *buf); +int proto_send(struct protocol_t *proto, void *source, void *dest); +int proto_recv(struct protocol_t *proto, void *source, void *dest);
typedef struct protocol_vtable { /* Initialization function: Fills in the protocol vtable. */ - int (*init)(struct protocol_t *self); + int (*init)(int n_options, char **options, + struct protocol_params_t *params); /* Destructor: Destroys the protocol state. */ void (*destroy)(void *state);
/* Constructor: Creates a protocol object. */ - void *(*create)(struct protocol_t *proto_struct, - protocol_params_t *parameters); + void *(*create)(struct protocol_t *proto_params, + struct protocol_params_t *parameters);
/* does handshake. Not all protocols have a handshake. */ int (*handshake)(void *state, @@ -67,12 +80,4 @@ typedef struct protocol_vtable {
} protocol_vtable;
-int set_up_protocol(int protocol); -struct protocol_t *proto_new(int protocol, - protocol_params_t *params); -void proto_destroy(struct protocol_t *proto); -int proto_handshake(struct protocol_t *proto, void *buf); -int proto_send(struct protocol_t *proto, void *source, void *dest); -int proto_recv(struct protocol_t *proto, void *source, void *dest); - #endif diff --git a/src/protocols/dummy.c b/src/protocols/dummy.c index 482c927..2a24b56 100644 --- a/src/protocols/dummy.c +++ b/src/protocols/dummy.c @@ -9,6 +9,7 @@ #include <event2/buffer.h>
#include "dummy.h" +#include "../network.h" #include "../util.h" #include "../protocol.h"
@@ -17,11 +18,55 @@ static int dummy_send(void *nothing, struct evbuffer *source, struct evbuffer *dest); static int dummy_recv(void *nothing, struct evbuffer *source, struct evbuffer *dest); +static void usage(void);
static protocol_vtable *vtable=NULL;
+/** + This function sets up the protocol and populates 'listner' + according to 'options'. + + 'options' is an array like this: + {"dummy","socks","127.0.0.1:6666"} +*/ int -dummy_init(void) { +dummy_init(int n_options, char **options, + struct protocol_params_t *params) +{ + struct sockaddr_storage ss_listen; + int sl_listen; + const char* defport; + + if (n_options != 3) + goto err; + + assert(!strcmp(options[0],"dummy")); + params->proto = DUMMY_PROTOCOL; + + if (!strcmp(options[1], "client")) { + defport = "48988"; /* bf5c */ + params->mode = LSN_SIMPLE_CLIENT; + } else if (!strcmp(options[1], "socks")) { + defport = "23548"; /* 5bf5 */ + params->mode = LSN_SOCKS_CLIENT; + } else if (!strcmp(options[1], "server")) { + defport = "11253"; /* 2bf5 */ + params->mode = LSN_SIMPLE_SERVER; + } else + goto err; + + if (resolve_address_port(options[2], 1, 1, + &ss_listen, &sl_listen, defport) < 0) { + printf("addr\n"); + goto err; + } + assert(sl_listen <= sizeof(struct sockaddr_storage)); + struct sockaddr *sa_listen=NULL; + sa_listen = (struct sockaddr *)&ss_listen; + memcpy(¶ms->on_address, sa_listen, sl_listen); + params->on_address_len = sl_listen; + + /* XXX memleak. */ vtable = calloc(1, sizeof(protocol_vtable)); if (!vtable) return -1; @@ -33,11 +78,30 @@ dummy_init(void) { vtable->recv = dummy_recv;
return 1; + + err: + usage(); + return -1; }
+static void +usage(void) +{ + printf("Great... You can't even form a dummy protocol line:\n" + "dummy syntax:\n" + "\tdummy dummy_opts\n" + "\t'dummy_opts':\n" + "\t\tmode ~ server|client|socks\n" + "\t\tlisten address ~ host:port\n" + "Example:\n" + "\tobfsproxy dummy socks 127.0.0.1:5000\n"); +} + + + void * -dummy_new(struct protocol_t *proto_struct, - protocol_params_t *params) +dummy_new(struct protocol_t *proto_struct, + struct protocol_params_t *params) { proto_struct->vtable = vtable;
diff --git a/src/protocols/dummy.h b/src/protocols/dummy.h index 1ee0e02..a00248f 100644 --- a/src/protocols/dummy.h +++ b/src/protocols/dummy.h @@ -5,7 +5,8 @@ struct protocol_t; struct evbuffer; struct protocol_params_t;
-int dummy_init(void); -void *dummy_new(struct protocol_t *proto_struct, struct protocol_params_t *params); +int dummy_init(int n_options, char **options, struct protocol_params_t *lsn); +void *dummy_new(struct protocol_t *proto_struct, + struct protocol_params_t *params);
#endif diff --git a/src/protocols/obfs2.c b/src/protocols/obfs2.c index a8f9155..41a97aa 100644 --- a/src/protocols/obfs2.c +++ b/src/protocols/obfs2.c @@ -17,6 +17,7 @@
#include "obfs2_crypt.h" #include "obfs2.h" +#include "../network.h" #include "../util.h" #include "../protocol.h"
@@ -30,6 +31,9 @@ static void *obfs2_state_new(protocol_params_t *params); static int obfs2_state_set_shared_secret(void *s, const char *secret, size_t secretlen); +static int set_up_vtable(void); +static void usage(void); +
static protocol_vtable *vtable=NULL;
@@ -38,22 +42,136 @@ static protocol_vtable *vtable=NULL; Returns 0 on success, -1 on fail. */ int -obfs2_init(void) { +obfs2_init(int n_options, char **options, + struct protocol_params_t *params) +{ + struct sockaddr_storage ss_listen; + int sl_listen; + int got_dest=0; + int got_ss=0; + const char* defport; + + if ((n_options < 3) || (n_options > 5)) { + printf("wrong options number: %d\n", n_options); + goto err; + } + + assert(!strcmp(*options,"obfs2")); + params->proto = OBFS2_PROTOCOL; + options++; + + /* Now parse the optional arguments */ + while (!strncmp(*options,"--",2)) { + if (!strncmp(*options,"--dest=",7)) { + if (got_dest) + goto err; + struct sockaddr_storage ss_target; + struct sockaddr *sa_target=NULL; + int sl_target=0; + if (resolve_address_port(*options+7, 1, 0, + &ss_target, &sl_target, NULL) < 0) + goto err; + assert(sl_target <= sizeof(struct sockaddr_storage)); + sa_target = (struct sockaddr *)&ss_target; + memcpy(¶ms->target_address, sa_target, sl_target); + params->target_address_len = sl_target; + got_dest=1; + } else if (!strncmp(*options,"--shared-secret=",16)) { + if (got_ss) + goto err; + /* this is freed in protocol_params_free() */ + params->shared_secret = strdup(*options+16); + params->shared_secret_len = strlen(*options+16); + got_ss=1; + } else { + printf("Unknown argument.\n"); + goto err; + } + options++; + } + + if (!strcmp(*options, "client")) { + defport = "48988"; /* bf5c */ + params->mode = LSN_SIMPLE_CLIENT; + } else if (!strcmp(*options, "socks")) { + defport = "23548"; /* 5bf5 */ + params->mode = LSN_SOCKS_CLIENT; + } else if (!strcmp(*options, "server")) { + defport = "11253"; /* 2bf5 */ + params->mode = LSN_SIMPLE_SERVER; + } else { + printf("only client/socks/server modes supported.\n"); + goto err; + } + options++; + + params->is_initiator = (params->mode != LSN_SIMPLE_SERVER); + + if (resolve_address_port(*options, 1, 1, + &ss_listen, &sl_listen, defport) < 0) + goto err; + assert(sl_listen <= sizeof(struct sockaddr_storage)); + struct sockaddr *sa_listen=NULL; + sa_listen = (struct sockaddr *)&ss_listen; + memcpy(¶ms->on_address, sa_listen, sl_listen); + params->on_address_len = sl_listen; + + /* Validate option selection. */ + if (got_dest && (params->mode == LSN_SOCKS_CLIENT)) { + printf("You can't be on socks mode and have --dest.\n"); + goto err; + } + + if (!got_dest && (params->mode != LSN_SOCKS_CLIENT)) { + printf("client/server mode needs --dest.\n"); + goto err; + } + + if (!set_up_vtable()) + return -1; + + if (initialize_crypto() < 0) { + fprintf(stderr, "Can't initialize crypto; failing\n"); + return -1; + } + + return 1; + err: + usage(); + return -1; +} + +static void +usage(void) +{ + printf("You failed at creating an understandable command.\n" + "obfs2 syntax:\n" + "\tobfs2 [obfs2_args] obfs2_opts\n" + "\t'obfs2_opts':\n" + "\t\tmode ~ server|client|socks\n" + "\t\tlisten address ~ host:port\n" + "\t'obfs2_args':\n" + "\t\tDestination Address ~ --dest=host:port\n" + "\t\tShared Secret ~ --shared-secret=<secret>\n" + "\tExample:\n" + "\tobfsproxy --dest=127.0.0.1:666 --shared-secret=himitsu " + "\tobfs2 server 127.0.0.1:1026\n"); +} + +static int +set_up_vtable(void) +{ + /* XXX memleak. */ vtable = calloc(1, sizeof(protocol_vtable)); if (!vtable) - return -1; + return 0;
vtable->destroy = obfs2_state_free; vtable->create = obfs2_new; vtable->handshake = obfs2_send_initial_message; vtable->send = obfs2_send; vtable->recv = obfs2_recv; - - if (initialize_crypto() < 0) { - fprintf(stderr, "Can't initialize crypto; failing\n"); - return -1; - } - + return 1; }
@@ -205,6 +323,7 @@ obfs2_state_set_shared_secret(void *s, const char *secret, uchar buf[SHARED_SECRET_LENGTH]; obfs2_state_t *state = s;
+ /* ASN we must say in spec that we hash command line shared secret. */ digest_t *c = digest_new(); digest_update(c, (uchar*)secret, secretlen); digest_getdigest(c, buf, sizeof(buf)); diff --git a/src/protocols/obfs2.h b/src/protocols/obfs2.h index 0d70144..7747330 100644 --- a/src/protocols/obfs2.h +++ b/src/protocols/obfs2.h @@ -14,11 +14,12 @@ typedef struct obfs2_state_t obfs2_state_t; struct evbuffer; struct protocol_t; struct protocol_params_t; +struct listener_t;
#define SHARED_SECRET_LENGTH SHA256_LENGTH
-int obfs2_init(void); -void *obfs2_new(struct protocol_t *proto_struct, +int obfs2_init(int n_options, char **options, struct protocol_params_t *params); +void *obfs2_new(struct protocol_t *proto_struct, struct protocol_params_t *params);
diff --git a/src/socks.h b/src/socks.h index 7b35cb5..20fd610 100644 --- a/src/socks.h +++ b/src/socks.h @@ -102,7 +102,6 @@ int socks5_send_reply(struct evbuffer *reply_dest, socks_state_t *state, int status); enum req_status socks5_handle_request(struct evbuffer *source, struct parsereq *parsereq);
- int socks4_read_request(struct evbuffer *source, socks_state_t *state); int socks4_send_reply(struct evbuffer *dest, socks_state_t *state, int status);