[tor-commits] [obfsproxy/master] Implements the parsing logic of the new CLI.

nickm at torproject.org nickm at torproject.org
Thu Jun 9 21:05:15 UTC 2011


commit 1d3d01d5b22ea60614936d7850dddf493a96c0fc
Author: George Kadianakis <desnacked at 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;
 }





More information about the tor-commits mailing list