-more
authorMartin Schanzenbach <mschanzenbach@posteo.de>
Fri, 1 Jun 2012 12:37:50 +0000 (12:37 +0000)
committerMartin Schanzenbach <mschanzenbach@posteo.de>
Fri, 1 Jun 2012 12:37:50 +0000 (12:37 +0000)
src/gns/gns_proxy_proto.h
src/gns/gnunet-gns-proxy.c

index 85a203d7d083031e20ab7bcbdefc67b56846d94c..39f7e881c551fe3aa3b5c70894a691a3407c3b31 100644 (file)
@@ -1,4 +1,6 @@
 
+#define SOCKS_VERSION_5 0x05
+#define SOCKS_AUTH_NONE 0
 
 /* The socks phases */
 enum
index a2e4ee6a51d305815b8998f931fedaf2c848e2e7..1cc889d389bdf5196782d1c92ea78a104092dc9d 100644 (file)
 #include "platform.h"
 #include <gnunet_util_lib.h>
 #include "gns_proxy_proto.h"
+#include "gns.h"
 
 #define GNUNET_GNS_PROXY_PORT 7777
 
+//TODO maybe make this an api call
+/**
+ * Checks if name is in tld
+ *
+ * @param name the name to check
+ * @param tld the TLD to check for
+ * @return GNUNET_YES or GNUNET_NO
+ */
+int
+is_tld(const char* name, const char* tld)
+{
+  int offset = 0;
+
+  if (strlen(name) <= strlen(tld))
+  {
+    return GNUNET_NO;
+  }
+
+  offset = strlen(name)-strlen(tld);
+  if (strcmp (name+offset, tld) != 0)
+  {
+    GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
+               "%s is not in .%s TLD\n", name, tld);
+    return GNUNET_NO;
+  }
+
+  return GNUNET_YES;
+}
 
 struct Socks5Request
 {
@@ -31,10 +60,17 @@ struct Socks5Request
   struct Socks5Request *next;
 
   struct GNUNET_NETWORK_Handle *sock;
+  struct GNUNET_NETWORK_Handle *remote_sock;
 
   int state;
 
   GNUNET_SCHEDULER_TaskIdentifier rtask;
+  GNUNET_SCHEDULER_TaskIdentifier wtask;
+
+  char rbuf[512];
+  char wbuf[512];
+  unsigned int rbuf_len;
+  unsigned int wbuf_len;
 };
 
 struct Socks5Connections
@@ -49,6 +85,37 @@ static struct GNUNET_NETWORK_Handle *lsock;
 GNUNET_SCHEDULER_TaskIdentifier ltask;
 static struct Socks5Connections s5conns;
 
+/**
+ * Write data to socket
+ *
+ * @param cls the closure
+ * @param tc scheduler context
+ */
+static void
+do_write (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct Socks5Request *s5r = cls;
+  unsigned int len = s5r->wbuf_len;
+
+  s5r->wtask = GNUNET_SCHEDULER_NO_TASK;
+
+  if ((NULL != tc->read_ready) &&
+      (GNUNET_NETWORK_fdset_isset (tc->write_ready, s5r->sock)) &&
+      (len = GNUNET_NETWORK_socket_send (s5r->sock, &s5r->wbuf,
+                                         len)))
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Successfully sent %d bytes to socket\n",
+                len);
+  }
+  else
+  {
+    GNUNET_NETWORK_socket_close (s5r->sock);
+    GNUNET_free(s5r);
+    return;
+  }
+}
+
 /**
  * Read data from incoming connection
  *
@@ -59,14 +126,26 @@ static void
 do_read (void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 {
   struct Socks5Request *s5r = cls;
-  char rbuf[512];
   unsigned int len;
+  struct socks5_client_hello *c_hello;
+  struct socks5_server_hello *s_hello;
+  struct socks5_client_request *c_req;
+  struct socks5_server_response *s_resp;
+
+  char domain[256];
+  uint8_t dom_len;
+  uint16_t req_port;
+  struct hostent *phost;
+  uint32_t remote_ip;
+  struct sockaddr_in remote_addr;
+  struct in_addr *r_sin_addr;
 
   s5r->rtask = GNUNET_SCHEDULER_NO_TASK;
 
   if ((NULL != tc->write_ready) &&
       (GNUNET_NETWORK_fdset_isset (tc->read_ready, s5r->sock)) &&
-      (len = GNUNET_NETWORK_socket_recv (s5r->sock, &rbuf, sizeof (rbuf))))
+      (len = GNUNET_NETWORK_socket_recv (s5r->sock, &s5r->rbuf,
+                                         sizeof (s5r->rbuf))))
   {
     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                 "Successfully read %d bytes from socket\n",
@@ -82,10 +161,130 @@ do_read (void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 
   if (s5r->state == SOCKS5_INIT)
   {
-    //DO sth etc
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "SOCKS5 init\n");
+    c_hello = (struct socks5_client_hello*)&s5r->rbuf;
+
+    GNUNET_assert (c_hello->version == SOCKS_VERSION_5);
+
+    s_hello = (struct socks5_server_hello*)&s5r->wbuf;
+    s5r->wbuf_len = sizeof( struct socks5_server_hello );
+
+    s_hello->version = c_hello->version;
+    s_hello->auth_method = SOCKS_AUTH_NONE;
+
+    /* Write response to client */
+    s5r->wtask = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
+                                                s5r->sock,
+                                                &do_write, s5r);
+
+    s5r->rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
+                                                s5r->sock,
+                                                &do_read, s5r);
+
+    s5r->state = SOCKS5_REQUEST;
+    return;
+  }
+
+  if (s5r->state == SOCKS5_REQUEST)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Processing SOCKS5 request\n");
+    c_req = (struct socks5_client_request*)&s5r->rbuf;
+    s_resp = (struct socks5_server_response*)&s5r->wbuf;
+    s5r->wbuf_len = sizeof (struct socks5_server_response);
+
+    GNUNET_assert (c_req->addr_type == 3);
+
+    dom_len = *((uint8_t*)(&(c_req->addr_type) + 1));
+    memset(domain, 0, sizeof(domain));
+    strncpy(domain, (char*)(&(c_req->addr_type) + 2), dom_len);
+    req_port = *((uint16_t*)(&(c_req->addr_type) + 2 + dom_len));
+
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                "Requested connection is %s:%d\n",
+                domain,
+                ntohs(req_port));
+
+    if (is_tld (domain, GNUNET_GNS_TLD) ||
+        is_tld (domain, GNUNET_GNS_TLD_ZKEY))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "Requested connection is gnunet tld\n",
+                  domain);
+    }
+    else
+    {
+      phost = (struct hostent*)gethostbyname (domain);
+      if (phost == NULL)
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "Resolve %s error!\n", domain );
+        s_resp->version = 0x05;
+        s_resp->reply = 0x01;
+        s5r->wtask = 
+          GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
+                                          s5r->sock,
+                                          &do_write, s5r);
+        //ERROR!
+        //TODO! close socket after the write! schedule task
+        //GNUNET_NETWORK_socket_close (s5r->sock);
+        //GNUNET_free(s5r);
+        return;
+      }
+
+      s5r->remote_sock = GNUNET_NETWORK_socket_create (AF_INET,
+                                                       SOCK_STREAM,
+                                                       0);
+      r_sin_addr = (struct in_addr*)(phost->h_addr);
+      remote_ip = r_sin_addr->s_addr;
+      memset(&remote_addr, 0, sizeof(remote_addr));
+      remote_addr.sin_family = AF_INET;
+      remote_addr.sin_addr.s_addr = remote_ip;
+      remote_addr.sin_port = req_port;
+      
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "target server: %s:%u\n", inet_ntoa(remote_addr.sin_addr),
+                  ntohs(req_port));
+
+      GNUNET_assert ( s5r->remote_sock != NULL );
+
+      if (GNUNET_OK != 
+          GNUNET_NETWORK_socket_connect ( s5r->remote_sock,
+                                          (struct sockaddr*)&remote_addr,
+                                          sizeof (struct sockaddr)))
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "socket request error...\n");
+        s_resp->version = 0x05;
+        s_resp->reply = 0x01;
+        s5r->wtask =
+          GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
+                                          s5r->sock,
+                                          &do_write, s5r);
+        //TODO see above
+        return;
+      }
+
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                  "new remote connection\n");
+
+      s_resp->version = 0x05;
+      s_resp->reply = 0x00;
+      s_resp->reserved = 0x00;
+      s_resp->addr_type = 0x01;
+
+      s5r->state = SOCKS5_DATA_TRANSFER;
+
+      s5r->wtask =
+        GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
+                                        s5r->sock,
+                                        &do_write, s5r);
+
+    }
   }
 
-  GNUNET_CONTAINER_DLL_remove (s5conns.head, s5conns.tail, s5r);
+  //GNUNET_CONTAINER_DLL_remove (s5conns.head, s5conns.tail, s5r);
 
 }