[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[tor-commits] [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



commit d0cf5ae1f52fc3bf9daa4c3fb754cc77e4b74159
Author: Zack Weinberg <zackw@xxxxxxxxx>
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;



_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits