#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
{
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
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
*
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",
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);
}