commit 1d3d01d5b22ea60614936d7850dddf493a96c0fc Author: George Kadianakis desnacked@gmail.com Date: Sun May 29 04:02:10 2011 +0200
Implements the parsing logic of the new CLI. --- src/main.c | 257 +++++++++++++++++++++++++++++++++++++++++++----------------- 1 files changed, 186 insertions(+), 71 deletions(-)
diff --git a/src/main.c b/src/main.c index 4c3c48c..8f03df1 100644 --- a/src/main.c +++ b/src/main.c @@ -21,13 +21,25 @@
static void usage(void) __attribute__((noreturn));
+#define SEPERATOR "+" +#define MAXPROTOCOLS 20 + +const char *supported_protocols[] = { "obfs2", "dummy" }; +const int n_supported_protocols = 2; + static void usage(void) { + int i; fprintf(stderr, - "Usage: obfsproxy {client/server/socks} {obfs2/dummy} listenaddr[:port] targetaddr:port <shared secret>\n" - " (Default listen port is 48988 for client; 23548 for socks; 11253 for server)\n" - ); + "Usage: obfsproxy protocol_name [protocol_args] protocol_options %s protocol_name ...\n" + "Available protocols:", + SEPERATOR); + /* cheapie */ + for (i=0;i<n_supported_protocols;i++) + fprintf(stderr," [%s]", supported_protocols[i]); + fprintf(stderr,"\n"); + exit(1); }
@@ -36,109 +48,212 @@ handle_signal_cb(evutil_socket_t fd, short what, void *arg) { struct event_base *base = arg; /* int signum = (int) fd; */ - + event_base_loopexit(base, NULL); }
+/** + This function visits all the command line arguments in 'argv' between + 'start' and 'end' and writes them in 'options_string'. + */ +static int +populate_options(char **options_string, + const char **argv, int n_options) +{ + int x,g; + for (g=0;g<=n_options-1;g++) { + options_string[g] = strdup(argv[g]); + if (!options_string[x]) { + return -1; + } + } + return 0; +} + +/** + Runs through all the supported protocols and checks if 'name' + matches with the name of any of them. +*/ +static int +is_supported_protocol(const char *name) { + int f; + for (f=0;f<n_supported_protocols;f++) { + if (!strcmp(name,supported_protocols[f])) + return 1; + } + return 0; +} + int main(int argc, const char **argv) { - int protocol; - int is_client, is_socks = 0, mode; - struct sockaddr_storage ss_listen, ss_target; - struct sockaddr *sa_target=NULL; - int sl_listen, sl_target=0; - const char *defport; - char *shared_secret = NULL; - struct event_base *base; struct event *sigevent; - listener_t *listener;
- /* XXXXX the interface is crap. Fix that. XXXXX */ - if (argc < 4) - usage(); - if (!strcmp(argv[1], "client")) { - is_client = 1; - defport = "48988"; /* bf5c */ - mode = LSN_SIMPLE_CLIENT; - } else if (!strcmp(argv[1], "socks")) { - is_client = 1; - is_socks = 1; - defport = "23548"; /* 5bf5 */ - mode = LSN_SOCKS_CLIENT; - } else if (!strcmp(argv[1], "server")) { - is_client = 0; - defport = "11253"; /* 2bf5 */ - mode = LSN_SIMPLE_SERVER; - } else { + /* Yes, these are three stars right there. This is an array of + arrays of strings! Every element of the array is an array of + strings that contains all the options of a protocol. + At runtime it should look like this: + char protocol_options[<number of protocols>][<number of options>][<length of option>] + */ + char ***protocol_options = NULL; + /* This is an array of integers! Each integer is the number of + options of the respective protocol. */ + int *n_options_array = NULL; + /* This is an integer! It contains the number of protocols that we + managed to recognize, by their protocol name. Of course it's not + the *actual* actual_protocols since some of them could have wrong + options or arguments, but this will be resolved by + set_up_protocol() and listener_new(). */ + int actual_protocols=0; + + int start; + int end; + int n_options; + void *temp; + int i; + + unsigned int n_protocols=1; + unsigned int protocols[MAXPROTOCOLS+1]; + protocols[0] = 0; + + if (argc < 2) { usage(); }
- if (!strcmp(argv[2], "obfs2")) - protocol = OBFS2_PROTOCOL; - else if (!strcmp(argv[2], "dummy")) - protocol = DUMMY_PROTOCOL; - else - usage(); + /* Iterate through command line arguments and find protocols. */ + for (i=0;i<argc;i++) { + if (!strcmp(argv[i],SEPERATOR)) { + protocols[n_protocols] = i; + n_protocols++; + if (n_protocols > MAXPROTOCOLS) { + printf("Sorry, we only allow %d protocols. Don't ask me why. " + "Exiting.\n", MAXPROTOCOLS); + return 5; + } + } + } + protocols[n_protocols] = argc; + if (n_protocols > 1) + printf("Found %d protocols.\n", n_protocols);
- /* figure out what port(s) to listen on as client/server */ - if (resolve_address_port(argv[3], 1, 1, &ss_listen, &sl_listen, defport) < 0) - usage(); + /* Iterate through protocols. */ + for (i=0;i<n_protocols;i++) { + /* This "points" to the first argument of this protocol in argv. */ + start = protocols[i]+1; + /* This "points" to the last argument of this protocol in argv. */ + end = protocols[i+1]-1; + n_options = end-start+1;
- /* figure out what place to connect to as a client/server. */ - /* XXXX when we add socks support, clients will not have a fixed "target" - * XXXX address but will instead connect to a client-selected address. */ - if (resolve_address_port(argv[4], 1, 0, &ss_target, &sl_target, NULL) < 0) - usage(); - sa_target = (struct sockaddr *)&ss_target; + if (!is_supported_protocol(argv[start])) { + printf("We don't support crappy protocols, son.\n"); + continue; + }
- /* Let's see if the user wants a shared secret. - So ugly. So ugly. So ugly. So ugly. So ugly interface. - */ - if (argc > 5 && argc != 6) - usage(); - if (argc == 6) { - if (protocol != OBFS2_PROTOCOL) { - printf("shared secret is only supported with obfs2 atm.\n"); + /* Okay seems like we support this protocol. */ + actual_protocols++; + + /* We now allocate enough space for our parsing adventures. + + We first allocate space for a pointer in protocol_options, + which points to an array carrying the options of this protocol. + We then allocate space for the array carrying the options of + this protocol. + Finally, we allocate space on the n_options_array so that we + can put the number of options there. + */ + temp = + realloc(protocol_options, sizeof(char**)*actual_protocols); + if (!temp) exit(1); - } + protocol_options = temp; + /* We should now allocate some space for all the strings + carrying the protocol options. */ + protocol_options[actual_protocols-1] = + malloc(sizeof(char*)*(n_options)); + if (!protocol_options[actual_protocols-1]) + exit(1); + temp = realloc(n_options_array, sizeof(int)*actual_protocols); + if (!temp) + exit(1); + n_options_array = temp; + n_options_array[actual_protocols-1] = n_options;
- shared_secret = strdup(argv[5]); + /* Finally! Let's fill protocol_options. */ + populate_options(protocol_options[actual_protocols-1], + &argv[start], n_options); }
+ /* Excellent. Now we should have protocol_options populated with all + the protocol options we got from the user. */ + /* Initialize libevent */ base = event_base_new(); - if (base == NULL) { + if (!base) { fprintf(stderr, "Can't initialize Libevent; failing\n"); return 2; }
- if (is_socks && init_evdns_base(base) < 0) { + /* ASN should this happen only when SOCKS is enabled? */ + if (init_evdns_base(base) < 0) { fprintf(stderr, "Can't initialize evdns; failing\n"); return 3; } - + /* Handle signals */ signal(SIGPIPE, SIG_IGN); sigevent = evsignal_new(base, SIGINT, handle_signal_cb, (void*) base); - - /* start an evconnlistener on the appropriate port(s) */ - listener = listener_new(base, - mode, protocol, - (struct sockaddr *)&ss_listen, sl_listen, - sa_target, sl_target, - shared_secret, - shared_secret ? strlen(shared_secret) : 0); - if (! listener) { - printf("Couldn't create listener!\n"); + if (event_add(sigevent,NULL)) { + printf("Oh come on! We can't even add events for signals! Exiting.\n"); return 4; }
- /* run the event loop */ - event_base_dispatch(base); + /*Let's open a new listener for each protocol. */ + int h; + listener_t *listeners[actual_protocols]; + listener_t *temp_listener; + int n_listeners=0; + for (h=0;h<actual_protocols;h++) { + if (n_protocols > 1) { + printf("===========================\n" + "Spawning listener %d!\n" + "===========================\n", h+1); + } + + temp_listener = listener_new(base, n_options_array[h], protocol_options[h]); + + /** Free the space allocated for this protocol's options. */ + for (i=0;i<n_options_array[h];i++) + free(protocol_options[h][i]); + free(protocol_options[h]); + + if (!temp_listener) { + continue; + } + + printf("Succesfully created listener.\n"); + listeners[n_listeners] = temp_listener; + + n_listeners++; + } + + if (n_protocols > 1) { + printf("\n===========================\n" + "From the original %d protocols only %d were parsed from main.c. " + "In the end only %d survived.\n\nStarting up...\n" + "===========================\n", + n_protocols, actual_protocols,n_listeners); + } + + /* run the event loop if at least a listener was created. */ + if (n_listeners) + event_base_dispatch(base);
- listener_free(listener); + /* We are exiting. Clean everything. */ + for (h=0;h<n_listeners;h++) + listener_free(listeners[h]); + free(protocol_options); + free(n_options_array);
return 0; }