[or-cvs] [tor/master 26/38] Implement SOCKS-client support for bufferevents

nickm at torproject.org nickm at torproject.org
Mon Sep 27 20:51:00 UTC 2010


Author: Nick Mathewson <nickm at torproject.org>
Date: Wed, 26 Aug 2009 11:55:36 -0400
Subject: Implement SOCKS-client support for bufferevents
Commit: 9796b9bfa6a757780d6185547e4baf739c53cdac

---
 src/or/buffers.c    |   73 ++++++++++++++++++++++++++++++++++++++++----------
 src/or/buffers.h    |    2 +
 src/or/connection.c |   43 +++++++++++++++++++----------
 3 files changed, 88 insertions(+), 30 deletions(-)

diff --git a/src/or/buffers.c b/src/or/buffers.c
index ffdbcd3..b9e1c53 100644
--- a/src/or/buffers.c
+++ b/src/or/buffers.c
@@ -56,6 +56,9 @@
 static int parse_socks(const char *data, size_t datalen, socks_request_t *req,
                        int log_sockstype, int safe_socks, ssize_t *drain_out,
                        size_t *want_length_out);
+static int parse_socks_client(const uint8_t *data, size_t datalen,
+                              int state, char **reason,
+                              ssize_t *drain_out);
 
 /* Chunk manipulation functions */
 
@@ -1513,7 +1516,7 @@ fetch_from_evbuffer_socks(struct evbuffer *buf, socks_request_t *req,
     want_length = evbuffer_get_contiguous_space(buf);
     n_drain = 0;
     i = evbuffer_peek(buf, want_length, NULL, &v, 1);
-    tor_assert(i == i);
+    tor_assert(i == 1);
     data = v.iov_base;
     datalen = v.iov_len;
 
@@ -1900,21 +1903,61 @@ parse_socks(const char *data, size_t datalen, socks_request_t *req,
 int
 fetch_from_buf_socks_client(buf_t *buf, int state, char **reason)
 {
-  unsigned char *data;
-  size_t addrlen;
-
+  ssize_t drain = 0;
+  int r;
   if (buf->datalen < 2)
     return 0;
 
   buf_pullup(buf, 128, 0);
   tor_assert(buf->head && buf->head->datalen >= 2);
 
-  data = (unsigned char *) buf->head->data;
+  r = parse_socks_client((uint8_t*)buf->head->data, buf->head->datalen,
+                         state, reason, &drain);
+  if (drain > 0)
+    buf_remove_from_front(buf, drain);
+  else if (drain < 0)
+    buf_clear(buf);
+
+  return r;
+}
+
+#ifdef USE_BUFFEREVENTS
+/** As fetch_from_buf_socks_client, buf works on an evbuffer */
+int
+fetch_from_evbuffer_socks_client(struct evbuffer *buf, int state,
+                                 char **reason)
+{
+  ssize_t drain = 0;
+  uint8_t *data;
+  size_t datalen = evbuffer_get_contiguous_space(buf);
+  int r;
+
+  data = evbuffer_pullup(buf, 128);
+  r = parse_socks_client(data, datalen, state, reason, &drain);
+  if (drain > 0)
+    evbuffer_drain(buf, drain);
+  else
+    evbuffer_drain(buf, evbuffer_get_length(buf));
+
+  return r;
+}
+#endif
+
+/** Implementation logic for fetch_from_*_socks_client. */
+static int
+parse_socks_client(const uint8_t *data, size_t datalen,
+                   int state, char **reason,
+                   ssize_t *drain_out)
+{
+  unsigned int addrlen;
+  *drain_out = 0;
+  if (datalen < 2)
+    return 0;
 
   switch (state) {
     case PROXY_SOCKS4_WANT_CONNECT_OK:
       /* Wait for the complete response */
-      if (buf->head->datalen < 8)
+      if (datalen < 8)
         return 0;
 
       if (data[1] != 0x5a) {
@@ -1923,7 +1966,7 @@ fetch_from_buf_socks_client(buf_t *buf, int state, char **reason)
       }
 
       /* Success */
-      buf_remove_from_front(buf, 8);
+      *drain_out = 8;
       return 1;
 
     case PROXY_SOCKS5_WANT_AUTH_METHOD_NONE:
@@ -1935,7 +1978,7 @@ fetch_from_buf_socks_client(buf_t *buf, int state, char **reason)
       }
 
       log_info(LD_NET, "SOCKS 5 client: continuing without authentication");
-      buf_clear(buf);
+      *drain_out = -1;
       return 1;
 
     case PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929:
@@ -1945,11 +1988,11 @@ fetch_from_buf_socks_client(buf_t *buf, int state, char **reason)
         case 0x00:
           log_info(LD_NET, "SOCKS 5 client: we have auth details but server "
                             "doesn't require authentication.");
-          buf_clear(buf);
+          *drain_out = -1;
           return 1;
         case 0x02:
           log_info(LD_NET, "SOCKS 5 client: need authentication.");
-          buf_clear(buf);
+          *drain_out = -1;
           return 2;
         /* fall through */
       }
@@ -1966,7 +2009,7 @@ fetch_from_buf_socks_client(buf_t *buf, int state, char **reason)
       }
 
       log_info(LD_NET, "SOCKS 5 client: authentication successful.");
-      buf_clear(buf);
+      *drain_out = -1;
       return 1;
 
     case PROXY_SOCKS5_WANT_CONNECT_OK:
@@ -1975,7 +2018,7 @@ fetch_from_buf_socks_client(buf_t *buf, int state, char **reason)
        * the data used */
 
       /* wait for address type field to arrive */
-      if (buf->datalen < 4)
+      if (datalen < 4)
         return 0;
 
       switch (data[3]) {
@@ -1986,7 +2029,7 @@ fetch_from_buf_socks_client(buf_t *buf, int state, char **reason)
           addrlen = 16;
           break;
         case 0x03: /* fqdn (can this happen here?) */
-          if (buf->datalen < 5)
+          if (datalen < 5)
             return 0;
           addrlen = 1 + data[4];
           break;
@@ -1996,7 +2039,7 @@ fetch_from_buf_socks_client(buf_t *buf, int state, char **reason)
       }
 
       /* wait for address and port */
-      if (buf->datalen < 6 + addrlen)
+      if (datalen < 6 + addrlen)
         return 0;
 
       if (data[1] != 0x00) {
@@ -2004,7 +2047,7 @@ fetch_from_buf_socks_client(buf_t *buf, int state, char **reason)
         return -1;
       }
 
-      buf_remove_from_front(buf, 6 + addrlen);
+      *drain_out = 6 + addrlen;
       return 1;
   }
 
diff --git a/src/or/buffers.h b/src/or/buffers.h
index 4f565dd..64e1f55 100644
--- a/src/or/buffers.h
+++ b/src/or/buffers.h
@@ -53,6 +53,8 @@ int fetch_var_cell_from_evbuffer(struct evbuffer *buf, var_cell_t **out,
                                  int linkproto);
 int fetch_from_evbuffer_socks(struct evbuffer *buf, socks_request_t *req,
                               int log_sockstype, int safe_socks);
+int fetch_from_evbuffer_socks_client(struct evbuffer *buf, int state,
+                                     char **reason);
 int fetch_from_evbuffer_http(struct evbuffer *buf,
                         char **headers_out, size_t max_headerlen,
                         char **body_out, size_t *body_used, size_t max_bodylen,
diff --git a/src/or/connection.c b/src/or/connection.c
index 43f6c47..e688f4c 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -1572,6 +1572,19 @@ connection_send_socks5_connect(connection_t *conn)
   conn->proxy_state = PROXY_SOCKS5_WANT_CONNECT_OK;
 }
 
+/** DOCDOC */
+static int
+connection_fetch_from_buf_socks_client(connection_t *conn,
+                                       int state, char **reason)
+{
+  IF_HAS_BUFFEREVENT(conn, {
+    struct evbuffer *input = bufferevent_get_input(conn->bufev);
+    return fetch_from_evbuffer_socks_client(input, state, reason);
+  }) ELSE_IF_NO_BUFFEREVENT {
+    return fetch_from_buf_socks_client(conn->inbuf, state, reason);
+  }
+}
+
 /** Call this from connection_*_process_inbuf() to advance the proxy
  * handshake.
  *
@@ -1599,17 +1612,17 @@ connection_read_proxy_handshake(connection_t *conn)
       break;
 
     case PROXY_SOCKS4_WANT_CONNECT_OK:
-      ret = fetch_from_buf_socks_client(conn->inbuf,
-                                        conn->proxy_state,
-                                        &reason);
+      ret = connection_fetch_from_buf_socks_client(conn,
+                                                   conn->proxy_state,
+                                                   &reason);
       if (ret == 1)
         conn->proxy_state = PROXY_CONNECTED;
       break;
 
     case PROXY_SOCKS5_WANT_AUTH_METHOD_NONE:
-      ret = fetch_from_buf_socks_client(conn->inbuf,
-                                        conn->proxy_state,
-                                        &reason);
+      ret = connection_fetch_from_buf_socks_client(conn,
+                                                   conn->proxy_state,
+                                                   &reason);
       /* no auth needed, do connect */
       if (ret == 1) {
         connection_send_socks5_connect(conn);
@@ -1618,9 +1631,9 @@ connection_read_proxy_handshake(connection_t *conn)
       break;
 
     case PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929:
-      ret = fetch_from_buf_socks_client(conn->inbuf,
-                                        conn->proxy_state,
-                                        &reason);
+      ret = connection_fetch_from_buf_socks_client(conn,
+                                                   conn->proxy_state,
+                                                   &reason);
 
       /* send auth if needed, otherwise do connect */
       if (ret == 1) {
@@ -1655,9 +1668,9 @@ connection_read_proxy_handshake(connection_t *conn)
       break;
 
     case PROXY_SOCKS5_WANT_AUTH_RFC1929_OK:
-      ret = fetch_from_buf_socks_client(conn->inbuf,
-                                        conn->proxy_state,
-                                        &reason);
+      ret = connection_fetch_from_buf_socks_client(conn,
+                                                   conn->proxy_state,
+                                                   &reason);
       /* send the connect request */
       if (ret == 1) {
         connection_send_socks5_connect(conn);
@@ -1666,9 +1679,9 @@ connection_read_proxy_handshake(connection_t *conn)
       break;
 
     case PROXY_SOCKS5_WANT_CONNECT_OK:
-      ret = fetch_from_buf_socks_client(conn->inbuf,
-                                        conn->proxy_state,
-                                        &reason);
+      ret = connection_fetch_from_buf_socks_client(conn,
+                                                   conn->proxy_state,
+                                                   &reason);
       if (ret == 1)
         conn->proxy_state = PROXY_CONNECTED;
       break;
-- 
1.7.1




More information about the tor-commits mailing list