[tor-commits] [torsocks/osx] Split SOCKS functions into separate file
hoganrobert at torproject.org
hoganrobert at torproject.org
Sun Oct 23 18:27:16 UTC 2011
commit 91046642c2efa6bed622f524b95919563d2a40a5
Author: Robert Hogan <robert at roberthogan.net>
Date: Sat Feb 19 13:20:21 2011 +0000
Split SOCKS functions into separate file
---
src/Makefile.am | 4 +-
src/socks.c | 629 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/socks.h | 116 ++++++++++
src/torsocks.c | 572 +--------------------------------------------------
src/torsocks.h | 104 ---------
5 files changed, 748 insertions(+), 677 deletions(-)
diff --git a/src/Makefile.am b/src/Makefile.am
index cce43f2..cb69714 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -25,11 +25,11 @@ torsocksconfmanpage_DATA = torsocks.conf.5
# Install main library to $(prefix)/lib/tor (must match torsocks.in)
lib_LTLIBRARIES = libtorsocks.la
-libtorsocks_la_SOURCES = torsocks.c common.c parser.c dead_pool.c darwin_warts.c
+libtorsocks_la_SOURCES = torsocks.c common.c parser.c dead_pool.c darwin_warts.c socks.c
libtorsocks_la_LDFLAGS = -version-info 1:0:0
#libtorsocks_la_CFLAGS = -nostartfiles
-DISTCLEANFILES=parser.lo dead_pool.lo common.lo libtorsocks.lo tsocks.lo \
+DISTCLEANFILES=parser.lo dead_pool.lo common.lo libtorsocks.lo torsocks.lo darwin_warts.lo socks.lo\
config.cache config.log config.h Makefile \
aclocal.m4 config.status usewithtor torsocks \
autom4te.cache .libs .deps
diff --git a/src/socks.c b/src/socks.c
new file mode 100644
index 0000000..37b97f5
--- /dev/null
+++ b/src/socks.c
@@ -0,0 +1,629 @@
+/***************************************************************************
+ * *
+ * Copyright (C) 2000-2008 Shaun Clowes <delius at progsoc.org> *
+ * Copyright (C) 2008-2011 Robert Hogan <robert at roberthogan.net> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+/* PreProcessor Defines */
+#include <config.h>
+
+/*Defining _NONSTD_SOURCE causes library and kernel calls to behave as closely
+to Mac OS X 10.3's library and kernel calls as possible.*/
+#if defined(__APPLE__) || defined(__darwin__)
+/*
+From 'man compat' in OSX:
+64-BIT COMPILATION
+ When compiling for 64-bit architectures, the __LP64__ macro will be defined to 1, and UNIX conformance
+ is always on (the _DARWIN_FEATURE_UNIX_CONFORMANCE macro will also be defined to the SUS conformance
+ level). Defining _NONSTD_SOURCE will cause a compilation error.
+*/
+#if !defined(__LP64__)
+#define _NONSTD_SOURCE 1
+#endif
+#include <sys/socket.h>
+#endif
+
+
+#ifdef USE_GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+/* Header Files */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <string.h>
+#include <strings.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/poll.h>
+#include <sys/time.h>
+#include <pwd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <common.h>
+#include <pthread.h>
+#include <stdarg.h>
+#if !defined(__APPLE__) && !defined(__darwin__)
+#include <sys/socket.h>
+#endif
+#include <resolv.h>
+
+#include "parser.h"
+#include "socks.h"
+#include "dead_pool.h"
+
+static int connect_server(struct connreq *conn);
+static int send_socks_request(struct connreq *conn);
+static int send_socksv4_request(struct connreq *conn);
+static int send_socksv5_method(struct connreq *conn);
+static int send_socksv5_connect(struct connreq *conn);
+static int send_buffer(struct connreq *conn);
+static int recv_buffer(struct connreq *conn);
+static int read_socksv5_method(struct connreq *conn);
+static int read_socksv4_req(struct connreq *conn);
+static int read_socksv5_connect(struct connreq *conn);
+static int read_socksv5_auth(struct connreq *conn);
+static int send_socksv4a_request(struct connreq *conn, const char *onion_host);
+
+struct connreq *new_socks_request(int sockid, struct sockaddr_in *connaddr,
+ struct sockaddr_in *serveraddr,
+ struct serverent *path)
+{
+ struct connreq *newconn;
+
+ if ((newconn = malloc(sizeof(*newconn))) == NULL) {
+ /* Could not malloc, we're stuffed */
+ show_msg(MSGERR, "Could not allocate memory for new socks request\n");
+ return(NULL);
+ }
+
+ /* Add this connection to be proxied to the list */
+ memset(newconn, 0x0, sizeof(*newconn));
+ newconn->sockid = sockid;
+ newconn->state = UNSTARTED;
+ newconn->path = path;
+ memcpy(&(newconn->connaddr), connaddr, sizeof(newconn->connaddr));
+ memcpy(&(newconn->serveraddr), serveraddr, sizeof(newconn->serveraddr));
+ newconn->next = requests;
+ requests = newconn;
+
+ return(newconn);
+}
+
+void kill_socks_request(struct connreq *conn)
+{
+ struct connreq *connnode;
+
+ if (requests == conn)
+ requests = conn->next;
+ else {
+ for (connnode = requests; connnode != NULL; connnode = connnode->next) {
+ if (connnode->next == conn) {
+ connnode->next = conn->next;
+ break;
+ }
+ }
+ }
+
+ free(conn);
+}
+
+struct connreq *find_socks_request(int sockid, int includefinished)
+{
+ struct connreq *connnode;
+
+ for (connnode = requests; connnode != NULL; connnode = connnode->next) {
+ if (connnode->sockid == sockid) {
+ if (((connnode->state == FAILED) || (connnode->state == DONE)) &&
+ !includefinished)
+ break;
+ else
+ return(connnode);
+ }
+ }
+
+ return(NULL);
+}
+
+int handle_request(struct connreq *conn)
+{
+ int rc = 0;
+ int i = 0;
+
+ show_msg(MSGDEBUG, "Beginning handle loop for socket %d\n", conn->sockid);
+
+ while ((rc == 0) &&
+ (conn->state != FAILED) &&
+ (conn->state != DONE) &&
+ (i++ < 20)) {
+ show_msg(MSGDEBUG, "In request handle loop for socket %d, "
+ "current state of request is %d\n", conn->sockid,
+ conn->state);
+ switch(conn->state) {
+ case UNSTARTED:
+ case CONNECTING:
+ rc = connect_server(conn);
+ break;
+ case CONNECTED:
+ rc = send_socks_request(conn);
+ break;
+ case SENDING:
+ rc = send_buffer(conn);
+ break;
+ case RECEIVING:
+ rc = recv_buffer(conn);
+ break;
+ case SENTV4REQ:
+ show_msg(MSGDEBUG, "Receiving reply to SOCKS V4 connect request\n");
+ conn->datalen = sizeof(struct sockrep);
+ conn->datadone = 0;
+ conn->state = RECEIVING;
+ conn->nextstate = GOTV4REQ;
+ break;
+ case GOTV4REQ:
+ rc = read_socksv4_req(conn);
+ break;
+ case SENTV5METHOD:
+ show_msg(MSGDEBUG, "Receiving reply to SOCKS V5 method negotiation\n");
+ conn->datalen = 2;
+ conn->datadone = 0;
+ conn->state = RECEIVING;
+ conn->nextstate = GOTV5METHOD;
+ break;
+ case GOTV5METHOD:
+ rc = read_socksv5_method(conn);
+ break;
+ case SENTV5AUTH:
+ show_msg(MSGDEBUG, "Receiving reply to SOCKS V5 authentication negotiation\n");
+ conn->datalen = 2;
+ conn->datadone = 0;
+ conn->state = RECEIVING;
+ conn->nextstate = GOTV5AUTH;
+ break;
+ case GOTV5AUTH:
+ rc = read_socksv5_auth(conn);
+ break;
+ case SENTV5CONNECT:
+ show_msg(MSGDEBUG, "Receiving reply to SOCKS V5 connect request\n");
+ conn->datalen = 10;
+ conn->datadone = 0;
+ conn->state = RECEIVING;
+ conn->nextstate = GOTV5CONNECT;
+ break;
+ case GOTV5CONNECT:
+ rc = read_socksv5_connect(conn);
+ break;
+ }
+ conn->err = errno;
+ }
+
+ if (i == 20)
+ show_msg(MSGERR, "Ooops, state loop while handling request %d\n",
+ conn->sockid);
+
+ show_msg(MSGDEBUG, "Handle loop completed for socket %d in state %d, "
+ "returning %d\n", conn->sockid, conn->state, rc);
+ return(rc);
+}
+
+static int connect_server(struct connreq *conn)
+{
+ int rc;
+
+ /* Connect this socket to the socks server */
+ show_msg(MSGDEBUG, "Connecting to %s port %d\n",
+ inet_ntoa(conn->serveraddr.sin_addr), ntohs(conn->serveraddr.sin_port));
+
+ rc = realconnect(conn->sockid, (CONNECT_SOCKARG) &(conn->serveraddr),
+ sizeof(conn->serveraddr));
+
+ show_msg(MSGDEBUG, "Connect returned %d, errno is %d\n", rc, errno);
+ if (rc && errno == EISCONN) {
+ rc = 0;
+ show_msg(MSGDEBUG, "Socket %d already connected to SOCKS server\n", conn->sockid);
+ conn->state = CONNECTED;
+ } else if (rc) {
+ if (errno != EINPROGRESS) {
+ show_msg(MSGERR, "Error %d attempting to connect to SOCKS "
+ "server (%s)\n", errno, strerror(errno));
+ conn->state = FAILED;
+ } else {
+ show_msg(MSGDEBUG, "Connection in progress\n");
+ conn->state = CONNECTING;
+ }
+ } else {
+ show_msg(MSGDEBUG, "Socket %d connected to SOCKS server\n", conn->sockid);
+ conn->state = CONNECTED;
+ }
+
+ return((rc ? errno : 0));
+}
+
+static int send_socks_request(struct connreq *conn)
+{
+ int rc = 0;
+
+ if (conn->path->type == 4) {
+ char *name = get_pool_entry(pool, &(conn->connaddr.sin_addr));
+ if(name != NULL)
+ rc = send_socksv4a_request(conn,name);
+ else
+ rc = send_socksv4_request(conn);
+ } else
+ rc = send_socksv5_method(conn);
+ return(rc);
+}
+
+static int send_socksv4a_request(struct connreq *conn,const char *onion_host)
+{
+ struct passwd *user;
+ struct sockreq *thisreq;
+ int endOfUser;
+ /* Determine the current username */
+ user = getpwuid(getuid());
+
+ thisreq = (struct sockreq *) conn->buffer;
+ endOfUser=sizeof(struct sockreq) +
+ (user == NULL ? 0 : strlen(user->pw_name)) + 1;
+
+ /* Check the buffer has enough space for the request */
+ /* and the user name */
+ conn->datalen = endOfUser+
+ (onion_host == NULL ? 0 : strlen(onion_host)) + 1;
+ if (sizeof(conn->buffer) < conn->datalen) {
+ show_msg(MSGERR, "The SOCKS username is too long");
+ conn->state = FAILED;
+ return(ECONNREFUSED);
+ }
+
+ /* Create the request */
+ thisreq->version = 4;
+ thisreq->command = 1;
+ thisreq->dstport = conn->connaddr.sin_port;
+ thisreq->dstip = htonl(1);
+
+ /* Copy the username */
+ strcpy((char *) thisreq + sizeof(struct sockreq),
+ (user == NULL ? "" : user->pw_name));
+
+ /* Copy the onion host */
+ strcpy((char *) thisreq + endOfUser,
+ (onion_host == NULL ? "" : onion_host));
+
+ conn->datadone = 0;
+ conn->state = SENDING;
+ conn->nextstate = SENTV4REQ;
+
+ return(0);
+}
+
+static int send_socksv4_request(struct connreq *conn)
+{
+ struct passwd *user;
+ struct sockreq *thisreq;
+
+ /* Determine the current username */
+ user = getpwuid(getuid());
+
+ thisreq = (struct sockreq *) conn->buffer;
+
+ /* Check the buffer has enough space for the request */
+ /* and the user name */
+ conn->datalen = sizeof(struct sockreq) +
+ (user == NULL ? 0 : strlen(user->pw_name)) + 1;
+ if (sizeof(conn->buffer) < conn->datalen) {
+ show_msg(MSGERR, "The SOCKS username is too long");
+ conn->state = FAILED;
+ return(ECONNREFUSED);
+ }
+
+ /* Create the request */
+ thisreq->version = 4;
+ thisreq->command = 1;
+ thisreq->dstport = conn->connaddr.sin_port;
+ thisreq->dstip = conn->connaddr.sin_addr.s_addr;
+
+ /* Copy the username */
+ strcpy((char *) thisreq + sizeof(struct sockreq),
+ (user == NULL ? "" : user->pw_name));
+
+ conn->datadone = 0;
+ conn->state = SENDING;
+ conn->nextstate = SENTV4REQ;
+
+ return(0);
+}
+
+static int send_socksv5_method(struct connreq *conn)
+{
+ char verstring[] = { 0x05, /* Version 5 SOCKS */
+ 0x02, /* No. Methods */
+ 0x00, /* Null Auth */
+ 0x02 }; /* User/Pass Auth */
+
+ show_msg(MSGDEBUG, "Constructing V5 method negotiation\n");
+ conn->state = SENDING;
+ conn->nextstate = SENTV5METHOD;
+ memcpy(conn->buffer, verstring, sizeof(verstring));
+ conn->datalen = sizeof(verstring);
+ conn->datadone = 0;
+
+ return(0);
+}
+
+static int send_socksv5_connect(struct connreq *conn)
+{
+ int namelen = 0;
+ char *name = NULL;
+ char constring[] = { 0x05, /* Version 5 SOCKS */
+ 0x01, /* Connect request */
+ 0x00, /* Reserved */
+ 0x01 }; /* IP Version 4 */
+
+ show_msg(MSGDEBUG, "Constructing V5 connect request\n");
+ conn->datadone = 0;
+ conn->state = SENDING;
+ conn->nextstate = SENTV5CONNECT;
+ memcpy(conn->buffer, constring, sizeof(constring));
+ conn->datalen = sizeof(constring);
+
+ show_msg(MSGDEBUG, "send_socksv5_connect: looking for: %s\n",
+ inet_ntoa(conn->connaddr.sin_addr));
+
+ name = get_pool_entry(pool, &(conn->connaddr.sin_addr));
+ if(name != NULL) {
+ namelen = strlen(name);
+ if(namelen > 255) /* "Can't happen" */
+ name = NULL;
+ }
+ if(name != NULL) {
+ show_msg(MSGDEBUG, "send_socksv5_connect: found it!\n");
+ /* Substitute the domain name from the pool into the SOCKS request. */
+ conn->buffer[3] = 0x03; /* Change the ATYP field */
+ conn->buffer[4] = namelen; /* Length of name */
+ conn->datalen++;
+ memcpy(&conn->buffer[conn->datalen], name, namelen);
+ conn->datalen += namelen;
+ } else {
+ show_msg(MSGDEBUG, "send_socksv5_connect: ip address not found\n");
+ /* Use the raw IP address */
+ memcpy(&conn->buffer[conn->datalen], &(conn->connaddr.sin_addr.s_addr),
+ sizeof(conn->connaddr.sin_addr.s_addr));
+ conn->datalen += sizeof(conn->connaddr.sin_addr.s_addr);
+ }
+ memcpy(&conn->buffer[conn->datalen], &(conn->connaddr.sin_port),
+ sizeof(conn->connaddr.sin_port));
+ conn->datalen += sizeof(conn->connaddr.sin_port);
+
+ return(0);
+}
+
+static int send_buffer(struct connreq *conn)
+{
+ int rc = 0;
+
+ show_msg(MSGDEBUG, "Writing to server (sending %d bytes)\n", conn->datalen);
+ while ((rc == 0) && (conn->datadone != conn->datalen)) {
+ rc = send(conn->sockid, conn->buffer + conn->datadone,
+ conn->datalen - conn->datadone, 0);
+ if (rc > 0) {
+ conn->datadone += rc;
+ rc = 0;
+ } else {
+ if (errno != EWOULDBLOCK)
+ show_msg(MSGDEBUG, "Write failed, %s\n", strerror(errno));
+ rc = errno;
+ }
+ }
+
+ if (conn->datadone == conn->datalen)
+ conn->state = conn->nextstate;
+
+ show_msg(MSGDEBUG, "Sent %d bytes of %d bytes in buffer, return code is %d\n",
+ conn->datadone, conn->datalen, rc);
+ return(rc);
+}
+
+static int recv_buffer(struct connreq *conn)
+{
+ int rc = 0;
+
+ show_msg(MSGDEBUG, "Reading from server (expecting %d bytes)\n", conn->datalen);
+ while ((rc == 0) && (conn->datadone != conn->datalen)) {
+ rc = recv(conn->sockid, conn->buffer + conn->datadone,
+ conn->datalen - conn->datadone, 0);
+ if (rc > 0) {
+ conn->datadone += rc;
+ rc = 0;
+ } else if (rc == 0) {
+ show_msg(MSGDEBUG, "Peer has shutdown but we only read %d of %d bytes.\n",
+ conn->datadone, conn->datalen);
+ rc = ENOTCONN; /* ENOTCONN seems like the most fitting error message */
+ } else {
+ if (errno != EWOULDBLOCK)
+ show_msg(MSGDEBUG, "Read failed, %s\n", strerror(errno));
+ rc = errno;
+ }
+ }
+
+ if (conn->datadone == conn->datalen)
+ conn->state = conn->nextstate;
+
+ show_msg(MSGDEBUG, "Received %d bytes of %d bytes expected, return code is %d\n",
+ conn->datadone, conn->datalen, rc);
+ return(rc);
+}
+
+static int read_socksv5_method(struct connreq *conn)
+{
+ struct passwd *nixuser;
+ char *uname, *upass;
+
+ /* See if we offered an acceptable method */
+ if (conn->buffer[1] == '\xff') {
+ show_msg(MSGERR, "SOCKS V5 server refused authentication methods\n");
+ conn->state = FAILED;
+ return(ECONNREFUSED);
+ }
+
+ /* If the socks server chose username/password authentication */
+ /* (method 2) then do that */
+ if ((unsigned short int) conn->buffer[1] == 2) {
+ show_msg(MSGDEBUG, "SOCKS V5 server chose username/password authentication\n");
+
+ /* Determine the current *nix username */
+ nixuser = getpwuid(getuid());
+
+ if (((uname = conn->path->defuser) == NULL) &&
+ ((uname = getenv("TORSOCKS_USERNAME")) == NULL) &&
+ ((uname = (nixuser == NULL ? NULL : nixuser->pw_name)) == NULL)) {
+ show_msg(MSGERR, "Could not get SOCKS username from "
+ "local passwd file, torsocks.conf "
+ "or $TORSOCKS_USERNAME to authenticate "
+ "with");
+ conn->state = FAILED;
+ return(ECONNREFUSED);
+ }
+
+ if (((upass = getenv("TORSOCKS_PASSWORD")) == NULL) &&
+ ((upass = conn->path->defpass) == NULL)) {
+ show_msg(MSGERR, "Need a password in torsocks.conf or "
+ "$TORSOCKS_PASSWORD to authenticate with");
+ conn->state = FAILED;
+ return(ECONNREFUSED);
+ }
+
+ /* Check that the username / pass specified will */
+ /* fit into the buffer */
+ if ((3 + strlen(uname) + strlen(upass)) >= sizeof(conn->buffer)) {
+ show_msg(MSGERR, "The supplied socks username or "
+ "password is too long");
+ conn->state = FAILED;
+ return(ECONNREFUSED);
+ }
+
+ conn->datalen = 0;
+ conn->buffer[conn->datalen] = '\x01';
+ conn->datalen++;
+ conn->buffer[conn->datalen] = (int8_t) strlen(uname);
+ conn->datalen++;
+ memcpy(&(conn->buffer[conn->datalen]), uname, strlen(uname));
+ conn->datalen = conn->datalen + strlen(uname);
+ conn->buffer[conn->datalen] = (int8_t) strlen(upass);
+ conn->datalen++;
+ memcpy(&(conn->buffer[conn->datalen]), upass, strlen(upass));
+ conn->datalen = conn->datalen + strlen(upass);
+
+ conn->state = SENDING;
+ conn->nextstate = SENTV5AUTH;
+ conn->datadone = 0;
+ } else
+ return(send_socksv5_connect(conn));
+
+ return(0);
+}
+
+static int read_socksv5_auth(struct connreq *conn)
+{
+
+ if (conn->buffer[1] != '\x00') {
+ show_msg(MSGERR, "SOCKS authentication failed, check username and password\n");
+ conn->state = FAILED;
+ return(ECONNREFUSED);
+ }
+
+ /* Ok, we authenticated ok, send the connection request */
+ return(send_socksv5_connect(conn));
+}
+
+static int read_socksv5_connect(struct connreq *conn)
+{
+
+ /* See if the connection succeeded */
+ if (conn->buffer[1] != '\x00') {
+ show_msg(MSGERR, "SOCKS V5 connect failed: ");
+ conn->state = FAILED;
+ switch ((int8_t) conn->buffer[1]) {
+ case 1:
+ show_msg(MSGERR, "General SOCKS server failure\n");
+ return(ECONNABORTED);
+ case 2:
+ show_msg(MSGERR, "Connection denied by rule\n");
+ return(ECONNABORTED);
+ case 3:
+ show_msg(MSGERR, "Network unreachable\n");
+ return(ENETUNREACH);
+ case 4:
+ show_msg(MSGERR, "Host unreachable\n");
+ return(EHOSTUNREACH);
+ case 5:
+ show_msg(MSGERR, "Connection refused\n");
+ return(ECONNREFUSED);
+ case 6:
+ show_msg(MSGERR, "TTL Expired\n");
+ return(ETIMEDOUT);
+ case 7:
+ show_msg(MSGERR, "Command not supported\n");
+ return(ECONNABORTED);
+ case 8:
+ show_msg(MSGERR, "Address type not supported\n");
+ return(ECONNABORTED);
+ default:
+ show_msg(MSGERR, "Unknown error\n");
+ return(ECONNABORTED);
+ }
+ }
+ conn->state = DONE;
+
+ return(0);
+}
+
+static int read_socksv4_req(struct connreq *conn)
+{
+ struct sockrep *thisrep;
+
+ thisrep = (struct sockrep *) conn->buffer;
+
+ if (thisrep->result != 90) {
+ show_msg(MSGERR, "SOCKS V4 connect rejected:\n");
+ conn->state = FAILED;
+ switch(thisrep->result) {
+ case 91:
+ show_msg(MSGERR, "SOCKS server refused connection\n");
+ return(ECONNREFUSED);
+ case 92:
+ show_msg(MSGERR, "SOCKS server refused connection "
+ "because of failed connect to identd "
+ "on this machine\n");
+ return(ECONNREFUSED);
+ case 93:
+ show_msg(MSGERR, "SOCKS server refused connection "
+ "because identd and this library "
+ "reported different user-ids\n");
+ return(ECONNREFUSED);
+ default:
+ show_msg(MSGERR, "Unknown reason\n");
+ return(ECONNREFUSED);
+ }
+ }
+ conn->state = DONE;
+
+ return(0);
+}
diff --git a/src/socks.h b/src/socks.h
new file mode 100644
index 0000000..af26fa6
--- /dev/null
+++ b/src/socks.h
@@ -0,0 +1,116 @@
+/***************************************************************************
+ * *
+ * Copyright (C) 2000-2008 Shaun Clowes <delius at progsoc.org> *
+ * Copyright (C) 2008-2011 Robert Hogan <robert at roberthogan.net> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+/* socks.h - Structures used by torsocks to form SOCKS requests */
+
+#ifndef _SOCKS_H
+
+#define _SOCKS_H 1
+
+#include "parser.h"
+#include "dead_pool.h"
+
+/* Structure representing a socks connection request */
+struct sockreq {
+ int8_t version;
+ int8_t command;
+ int16_t dstport;
+ int32_t dstip;
+ /* A null terminated username goes here */
+};
+
+/* Structure representing a socks connection request response */
+struct sockrep {
+ int8_t version;
+ int8_t result;
+ int16_t ignore1;
+ int32_t ignore2;
+};
+
+/* Structure representing a socket which we are currently proxying */
+struct connreq {
+ /* Information about the socket and target */
+ int sockid;
+ struct sockaddr_in connaddr;
+ struct sockaddr_in serveraddr;
+
+ /* Pointer to the config entry for the socks server */
+ struct serverent *path;
+
+ /* Current state of this proxied socket */
+ int state;
+
+ /* Next state to go to when the send or receive is finished */
+ int nextstate;
+
+ /* When connections fail but an error number cannot be reported
+ * because the socket is non blocking we keep the connreq struct until
+ * the status is queried with connect() again, we then return
+ * this value */
+ int err;
+
+ /* Events that were set for this socket upon call to select() or
+ * poll() */
+ int selectevents;
+
+ /* Buffer for sending and receiving on the socket */
+ unsigned int datalen;
+ unsigned int datadone;
+ char buffer[2048];
+
+ struct connreq *next;
+};
+
+/* Connection statuses */
+#define UNSTARTED 0
+#define CONNECTING 1
+#define CONNECTED 2
+#define SENDING 3
+#define RECEIVING 4
+#define SENTV4REQ 5
+#define GOTV4REQ 6
+#define SENTV5METHOD 7
+#define GOTV5METHOD 8
+#define SENTV5AUTH 9
+#define GOTV5AUTH 10
+#define SENTV5CONNECT 11
+#define GOTV5CONNECT 12
+#define DONE 13
+#define FAILED 14
+
+/* Flags to indicate what events a socket was select()ed for */
+#define READ (1<<0)
+#define WRITE (1<<1)
+#define EXCEPT (1<<2)
+#define READWRITE (READ|WRITE)
+#define READWRITEEXCEPT (READ|WRITE|EXCEPT)
+
+/* Global Declarations */
+static dead_pool *pool = NULL;
+static struct connreq *requests = NULL;
+
+struct connreq *new_socks_request(int sockid, struct sockaddr_in *connaddr,
+ struct sockaddr_in *serveraddr,
+ struct serverent *path);
+void kill_socks_request(struct connreq *conn);
+struct connreq *find_socks_request(int sockid, int includefailed);
+int handle_request(struct connreq *conn);
+
+#endif
diff --git a/src/torsocks.c b/src/torsocks.c
index 4239ced..98af4b0 100644
--- a/src/torsocks.c
+++ b/src/torsocks.c
@@ -71,7 +71,7 @@ const char *torsocks_progname = "libtorsocks"; /* Name used in err msgs
#include <resolv.h>
#include "parser.h"
-#include "torsocks.h"
+#include "socks.h"
#include "dead_pool.h"
/* Some function names are macroized on Darwin. Allow those names
@@ -79,9 +79,6 @@ const char *torsocks_progname = "libtorsocks"; /* Name used in err msgs
#define EXPAND_GUTS(x) torsocks_##x##_guts
#define EXPAND_GUTS_NAME(x) EXPAND_GUTS(x)
-/* Global Declarations */
-static dead_pool *pool = NULL;
-
/* Function prototypes for original functions that we patch */
#ifdef SUPPORT_RES_API
int (*realres_init)(void);
@@ -92,7 +89,6 @@ int (*realres_init)(void);
#undef DARWIN_EXPANSION
static struct parsedfile config;
-static struct connreq *requests = NULL;
static int suid = 0;
static char *conffile = NULL;
static volatile int torsocks_init_complete = 0;
@@ -120,27 +116,7 @@ int res_init(void);
static int get_config();
static int get_environment();
-static int connect_server(struct connreq *conn);
-static int send_socks_request(struct connreq *conn);
-static struct connreq *new_socks_request(int sockid, struct sockaddr_in *connaddr,
- struct sockaddr_in *serveraddr,
- struct serverent *path);
-static void kill_socks_request(struct connreq *conn);
-static int handle_request(struct connreq *conn);
-static struct connreq *find_socks_request(int sockid, int includefailed);
-static int connect_server(struct connreq *conn);
-static int send_socks_request(struct connreq *conn);
-static int send_socksv4_request(struct connreq *conn);
-static int send_socksv5_method(struct connreq *conn);
-static int send_socksv5_connect(struct connreq *conn);
-static int send_buffer(struct connreq *conn);
-static int recv_buffer(struct connreq *conn);
-static int read_socksv5_method(struct connreq *conn);
-static int read_socksv4_req(struct connreq *conn);
-static int read_socksv5_connect(struct connreq *conn);
-static int read_socksv5_auth(struct connreq *conn);
static int deadpool_init(void);
-static int send_socksv4a_request(struct connreq *conn, const char *onion_host);
static pthread_mutex_t torsocks_init_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -898,552 +874,6 @@ int torsocks_getpeername_guts(GETPEERNAME_SIGNATURE,
return rc;
}
-static struct connreq *new_socks_request(int sockid, struct sockaddr_in *connaddr,
- struct sockaddr_in *serveraddr,
- struct serverent *path)
-{
- struct connreq *newconn;
-
- if ((newconn = malloc(sizeof(*newconn))) == NULL) {
- /* Could not malloc, we're stuffed */
- show_msg(MSGERR, "Could not allocate memory for new socks request\n");
- return(NULL);
- }
-
- /* Add this connection to be proxied to the list */
- memset(newconn, 0x0, sizeof(*newconn));
- newconn->sockid = sockid;
- newconn->state = UNSTARTED;
- newconn->path = path;
- memcpy(&(newconn->connaddr), connaddr, sizeof(newconn->connaddr));
- memcpy(&(newconn->serveraddr), serveraddr, sizeof(newconn->serveraddr));
- newconn->next = requests;
- requests = newconn;
-
- return(newconn);
-}
-
-static void kill_socks_request(struct connreq *conn)
-{
- struct connreq *connnode;
-
- if (requests == conn)
- requests = conn->next;
- else {
- for (connnode = requests; connnode != NULL; connnode = connnode->next) {
- if (connnode->next == conn) {
- connnode->next = conn->next;
- break;
- }
- }
- }
-
- free(conn);
-}
-
-static struct connreq *find_socks_request(int sockid, int includefinished)
-{
- struct connreq *connnode;
-
- for (connnode = requests; connnode != NULL; connnode = connnode->next) {
- if (connnode->sockid == sockid) {
- if (((connnode->state == FAILED) || (connnode->state == DONE)) &&
- !includefinished)
- break;
- else
- return(connnode);
- }
- }
-
- return(NULL);
-}
-
-static int handle_request(struct connreq *conn)
-{
- int rc = 0;
- int i = 0;
-
- show_msg(MSGDEBUG, "Beginning handle loop for socket %d\n", conn->sockid);
-
- while ((rc == 0) &&
- (conn->state != FAILED) &&
- (conn->state != DONE) &&
- (i++ < 20)) {
- show_msg(MSGDEBUG, "In request handle loop for socket %d, "
- "current state of request is %d\n", conn->sockid,
- conn->state);
- switch(conn->state) {
- case UNSTARTED:
- case CONNECTING:
- rc = connect_server(conn);
- break;
- case CONNECTED:
- rc = send_socks_request(conn);
- break;
- case SENDING:
- rc = send_buffer(conn);
- break;
- case RECEIVING:
- rc = recv_buffer(conn);
- break;
- case SENTV4REQ:
- show_msg(MSGDEBUG, "Receiving reply to SOCKS V4 connect request\n");
- conn->datalen = sizeof(struct sockrep);
- conn->datadone = 0;
- conn->state = RECEIVING;
- conn->nextstate = GOTV4REQ;
- break;
- case GOTV4REQ:
- rc = read_socksv4_req(conn);
- break;
- case SENTV5METHOD:
- show_msg(MSGDEBUG, "Receiving reply to SOCKS V5 method negotiation\n");
- conn->datalen = 2;
- conn->datadone = 0;
- conn->state = RECEIVING;
- conn->nextstate = GOTV5METHOD;
- break;
- case GOTV5METHOD:
- rc = read_socksv5_method(conn);
- break;
- case SENTV5AUTH:
- show_msg(MSGDEBUG, "Receiving reply to SOCKS V5 authentication negotiation\n");
- conn->datalen = 2;
- conn->datadone = 0;
- conn->state = RECEIVING;
- conn->nextstate = GOTV5AUTH;
- break;
- case GOTV5AUTH:
- rc = read_socksv5_auth(conn);
- break;
- case SENTV5CONNECT:
- show_msg(MSGDEBUG, "Receiving reply to SOCKS V5 connect request\n");
- conn->datalen = 10;
- conn->datadone = 0;
- conn->state = RECEIVING;
- conn->nextstate = GOTV5CONNECT;
- break;
- case GOTV5CONNECT:
- rc = read_socksv5_connect(conn);
- break;
- }
- conn->err = errno;
- }
-
- if (i == 20)
- show_msg(MSGERR, "Ooops, state loop while handling request %d\n",
- conn->sockid);
-
- show_msg(MSGDEBUG, "Handle loop completed for socket %d in state %d, "
- "returning %d\n", conn->sockid, conn->state, rc);
- return(rc);
-}
-
-static int connect_server(struct connreq *conn)
-{
- int rc;
-
- /* Connect this socket to the socks server */
- show_msg(MSGDEBUG, "Connecting to %s port %d\n",
- inet_ntoa(conn->serveraddr.sin_addr), ntohs(conn->serveraddr.sin_port));
-
- rc = realconnect(conn->sockid, (CONNECT_SOCKARG) &(conn->serveraddr),
- sizeof(conn->serveraddr));
-
- show_msg(MSGDEBUG, "Connect returned %d, errno is %d\n", rc, errno);
- if (rc && errno == EISCONN) {
- rc = 0;
- show_msg(MSGDEBUG, "Socket %d already connected to SOCKS server\n", conn->sockid);
- conn->state = CONNECTED;
- } else if (rc) {
- if (errno != EINPROGRESS) {
- show_msg(MSGERR, "Error %d attempting to connect to SOCKS "
- "server (%s)\n", errno, strerror(errno));
- conn->state = FAILED;
- } else {
- show_msg(MSGDEBUG, "Connection in progress\n");
- conn->state = CONNECTING;
- }
- } else {
- show_msg(MSGDEBUG, "Socket %d connected to SOCKS server\n", conn->sockid);
- conn->state = CONNECTED;
- }
-
- return((rc ? errno : 0));
-}
-
-static int send_socks_request(struct connreq *conn)
-{
- int rc = 0;
-
- if (conn->path->type == 4) {
- char *name = get_pool_entry(pool, &(conn->connaddr.sin_addr));
- if(name != NULL)
- rc = send_socksv4a_request(conn,name);
- else
- rc = send_socksv4_request(conn);
- } else
- rc = send_socksv5_method(conn);
- return(rc);
-}
-
-static int send_socksv4a_request(struct connreq *conn,const char *onion_host)
-{
- struct passwd *user;
- struct sockreq *thisreq;
- int endOfUser;
- /* Determine the current username */
- user = getpwuid(getuid());
-
- thisreq = (struct sockreq *) conn->buffer;
- endOfUser=sizeof(struct sockreq) +
- (user == NULL ? 0 : strlen(user->pw_name)) + 1;
-
- /* Check the buffer has enough space for the request */
- /* and the user name */
- conn->datalen = endOfUser+
- (onion_host == NULL ? 0 : strlen(onion_host)) + 1;
- if (sizeof(conn->buffer) < conn->datalen) {
- show_msg(MSGERR, "The SOCKS username is too long");
- conn->state = FAILED;
- return(ECONNREFUSED);
- }
-
- /* Create the request */
- thisreq->version = 4;
- thisreq->command = 1;
- thisreq->dstport = conn->connaddr.sin_port;
- thisreq->dstip = htonl(1);
-
- /* Copy the username */
- strcpy((char *) thisreq + sizeof(struct sockreq),
- (user == NULL ? "" : user->pw_name));
-
- /* Copy the onion host */
- strcpy((char *) thisreq + endOfUser,
- (onion_host == NULL ? "" : onion_host));
-
- conn->datadone = 0;
- conn->state = SENDING;
- conn->nextstate = SENTV4REQ;
-
- return(0);
-}
-
-static int send_socksv4_request(struct connreq *conn)
-{
- struct passwd *user;
- struct sockreq *thisreq;
-
- /* Determine the current username */
- user = getpwuid(getuid());
-
- thisreq = (struct sockreq *) conn->buffer;
-
- /* Check the buffer has enough space for the request */
- /* and the user name */
- conn->datalen = sizeof(struct sockreq) +
- (user == NULL ? 0 : strlen(user->pw_name)) + 1;
- if (sizeof(conn->buffer) < conn->datalen) {
- show_msg(MSGERR, "The SOCKS username is too long");
- conn->state = FAILED;
- return(ECONNREFUSED);
- }
-
- /* Create the request */
- thisreq->version = 4;
- thisreq->command = 1;
- thisreq->dstport = conn->connaddr.sin_port;
- thisreq->dstip = conn->connaddr.sin_addr.s_addr;
-
- /* Copy the username */
- strcpy((char *) thisreq + sizeof(struct sockreq),
- (user == NULL ? "" : user->pw_name));
-
- conn->datadone = 0;
- conn->state = SENDING;
- conn->nextstate = SENTV4REQ;
-
- return(0);
-}
-
-static int send_socksv5_method(struct connreq *conn)
-{
- char verstring[] = { 0x05, /* Version 5 SOCKS */
- 0x02, /* No. Methods */
- 0x00, /* Null Auth */
- 0x02 }; /* User/Pass Auth */
-
- show_msg(MSGDEBUG, "Constructing V5 method negotiation\n");
- conn->state = SENDING;
- conn->nextstate = SENTV5METHOD;
- memcpy(conn->buffer, verstring, sizeof(verstring));
- conn->datalen = sizeof(verstring);
- conn->datadone = 0;
-
- return(0);
-}
-
-static int send_socksv5_connect(struct connreq *conn)
-{
- int namelen = 0;
- char *name = NULL;
- char constring[] = { 0x05, /* Version 5 SOCKS */
- 0x01, /* Connect request */
- 0x00, /* Reserved */
- 0x01 }; /* IP Version 4 */
-
- show_msg(MSGDEBUG, "Constructing V5 connect request\n");
- conn->datadone = 0;
- conn->state = SENDING;
- conn->nextstate = SENTV5CONNECT;
- memcpy(conn->buffer, constring, sizeof(constring));
- conn->datalen = sizeof(constring);
-
- show_msg(MSGDEBUG, "send_socksv5_connect: looking for: %s\n",
- inet_ntoa(conn->connaddr.sin_addr));
-
- name = get_pool_entry(pool, &(conn->connaddr.sin_addr));
- if(name != NULL) {
- namelen = strlen(name);
- if(namelen > 255) /* "Can't happen" */
- name = NULL;
- }
- if(name != NULL) {
- show_msg(MSGDEBUG, "send_socksv5_connect: found it!\n");
- /* Substitute the domain name from the pool into the SOCKS request. */
- conn->buffer[3] = 0x03; /* Change the ATYP field */
- conn->buffer[4] = namelen; /* Length of name */
- conn->datalen++;
- memcpy(&conn->buffer[conn->datalen], name, namelen);
- conn->datalen += namelen;
- } else {
- show_msg(MSGDEBUG, "send_socksv5_connect: ip address not found\n");
- /* Use the raw IP address */
- memcpy(&conn->buffer[conn->datalen], &(conn->connaddr.sin_addr.s_addr),
- sizeof(conn->connaddr.sin_addr.s_addr));
- conn->datalen += sizeof(conn->connaddr.sin_addr.s_addr);
- }
- memcpy(&conn->buffer[conn->datalen], &(conn->connaddr.sin_port),
- sizeof(conn->connaddr.sin_port));
- conn->datalen += sizeof(conn->connaddr.sin_port);
-
- return(0);
-}
-
-static int send_buffer(struct connreq *conn)
-{
- int rc = 0;
-
- show_msg(MSGDEBUG, "Writing to server (sending %d bytes)\n", conn->datalen);
- while ((rc == 0) && (conn->datadone != conn->datalen)) {
- rc = send(conn->sockid, conn->buffer + conn->datadone,
- conn->datalen - conn->datadone, 0);
- if (rc > 0) {
- conn->datadone += rc;
- rc = 0;
- } else {
- if (errno != EWOULDBLOCK)
- show_msg(MSGDEBUG, "Write failed, %s\n", strerror(errno));
- rc = errno;
- }
- }
-
- if (conn->datadone == conn->datalen)
- conn->state = conn->nextstate;
-
- show_msg(MSGDEBUG, "Sent %d bytes of %d bytes in buffer, return code is %d\n",
- conn->datadone, conn->datalen, rc);
- return(rc);
-}
-
-static int recv_buffer(struct connreq *conn)
-{
- int rc = 0;
-
- show_msg(MSGDEBUG, "Reading from server (expecting %d bytes)\n", conn->datalen);
- while ((rc == 0) && (conn->datadone != conn->datalen)) {
- rc = recv(conn->sockid, conn->buffer + conn->datadone,
- conn->datalen - conn->datadone, 0);
- if (rc > 0) {
- conn->datadone += rc;
- rc = 0;
- } else if (rc == 0) {
- show_msg(MSGDEBUG, "Peer has shutdown but we only read %d of %d bytes.\n",
- conn->datadone, conn->datalen);
- rc = ENOTCONN; /* ENOTCONN seems like the most fitting error message */
- } else {
- if (errno != EWOULDBLOCK)
- show_msg(MSGDEBUG, "Read failed, %s\n", strerror(errno));
- rc = errno;
- }
- }
-
- if (conn->datadone == conn->datalen)
- conn->state = conn->nextstate;
-
- show_msg(MSGDEBUG, "Received %d bytes of %d bytes expected, return code is %d\n",
- conn->datadone, conn->datalen, rc);
- return(rc);
-}
-
-static int read_socksv5_method(struct connreq *conn)
-{
- struct passwd *nixuser;
- char *uname, *upass;
-
- /* See if we offered an acceptable method */
- if (conn->buffer[1] == '\xff') {
- show_msg(MSGERR, "SOCKS V5 server refused authentication methods\n");
- conn->state = FAILED;
- return(ECONNREFUSED);
- }
-
- /* If the socks server chose username/password authentication */
- /* (method 2) then do that */
- if ((unsigned short int) conn->buffer[1] == 2) {
- show_msg(MSGDEBUG, "SOCKS V5 server chose username/password authentication\n");
-
- /* Determine the current *nix username */
- nixuser = getpwuid(getuid());
-
- if (((uname = conn->path->defuser) == NULL) &&
- ((uname = getenv("TORSOCKS_USERNAME")) == NULL) &&
- ((uname = (nixuser == NULL ? NULL : nixuser->pw_name)) == NULL)) {
- show_msg(MSGERR, "Could not get SOCKS username from "
- "local passwd file, torsocks.conf "
- "or $TORSOCKS_USERNAME to authenticate "
- "with");
- conn->state = FAILED;
- return(ECONNREFUSED);
- }
-
- if (((upass = getenv("TORSOCKS_PASSWORD")) == NULL) &&
- ((upass = conn->path->defpass) == NULL)) {
- show_msg(MSGERR, "Need a password in torsocks.conf or "
- "$TORSOCKS_PASSWORD to authenticate with");
- conn->state = FAILED;
- return(ECONNREFUSED);
- }
-
- /* Check that the username / pass specified will */
- /* fit into the buffer */
- if ((3 + strlen(uname) + strlen(upass)) >= sizeof(conn->buffer)) {
- show_msg(MSGERR, "The supplied socks username or "
- "password is too long");
- conn->state = FAILED;
- return(ECONNREFUSED);
- }
-
- conn->datalen = 0;
- conn->buffer[conn->datalen] = '\x01';
- conn->datalen++;
- conn->buffer[conn->datalen] = (int8_t) strlen(uname);
- conn->datalen++;
- memcpy(&(conn->buffer[conn->datalen]), uname, strlen(uname));
- conn->datalen = conn->datalen + strlen(uname);
- conn->buffer[conn->datalen] = (int8_t) strlen(upass);
- conn->datalen++;
- memcpy(&(conn->buffer[conn->datalen]), upass, strlen(upass));
- conn->datalen = conn->datalen + strlen(upass);
-
- conn->state = SENDING;
- conn->nextstate = SENTV5AUTH;
- conn->datadone = 0;
- } else
- return(send_socksv5_connect(conn));
-
- return(0);
-}
-
-static int read_socksv5_auth(struct connreq *conn)
-{
-
- if (conn->buffer[1] != '\x00') {
- show_msg(MSGERR, "SOCKS authentication failed, check username and password\n");
- conn->state = FAILED;
- return(ECONNREFUSED);
- }
-
- /* Ok, we authenticated ok, send the connection request */
- return(send_socksv5_connect(conn));
-}
-
-static int read_socksv5_connect(struct connreq *conn)
-{
-
- /* See if the connection succeeded */
- if (conn->buffer[1] != '\x00') {
- show_msg(MSGERR, "SOCKS V5 connect failed: ");
- conn->state = FAILED;
- switch ((int8_t) conn->buffer[1]) {
- case 1:
- show_msg(MSGERR, "General SOCKS server failure\n");
- return(ECONNABORTED);
- case 2:
- show_msg(MSGERR, "Connection denied by rule\n");
- return(ECONNABORTED);
- case 3:
- show_msg(MSGERR, "Network unreachable\n");
- return(ENETUNREACH);
- case 4:
- show_msg(MSGERR, "Host unreachable\n");
- return(EHOSTUNREACH);
- case 5:
- show_msg(MSGERR, "Connection refused\n");
- return(ECONNREFUSED);
- case 6:
- show_msg(MSGERR, "TTL Expired\n");
- return(ETIMEDOUT);
- case 7:
- show_msg(MSGERR, "Command not supported\n");
- return(ECONNABORTED);
- case 8:
- show_msg(MSGERR, "Address type not supported\n");
- return(ECONNABORTED);
- default:
- show_msg(MSGERR, "Unknown error\n");
- return(ECONNABORTED);
- }
- }
- conn->state = DONE;
-
- return(0);
-}
-
-static int read_socksv4_req(struct connreq *conn)
-{
- struct sockrep *thisrep;
-
- thisrep = (struct sockrep *) conn->buffer;
-
- if (thisrep->result != 90) {
- show_msg(MSGERR, "SOCKS V4 connect rejected:\n");
- conn->state = FAILED;
- switch(thisrep->result) {
- case 91:
- show_msg(MSGERR, "SOCKS server refused connection\n");
- return(ECONNREFUSED);
- case 92:
- show_msg(MSGERR, "SOCKS server refused connection "
- "because of failed connect to identd "
- "on this machine\n");
- return(ECONNREFUSED);
- case 93:
- show_msg(MSGERR, "SOCKS server refused connection "
- "because identd and this library "
- "reported different user-ids\n");
- return(ECONNREFUSED);
- default:
- show_msg(MSGERR, "Unknown reason\n");
- return(ECONNREFUSED);
- }
- }
- conn->state = DONE;
-
- return(0);
-}
-
#ifdef SUPPORT_RES_API
int res_init(void)
{
diff --git a/src/torsocks.h b/src/torsocks.h
deleted file mode 100644
index 396aa5e..0000000
--- a/src/torsocks.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/***************************************************************************
- * *
- * Copyright (C) 2000-2008 Shaun Clowes <delius at progsoc.org> *
- * Copyright (C) 2008-2011 Robert Hogan <robert at roberthogan.net> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the *
- * Free Software Foundation, Inc., *
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
- ***************************************************************************/
-/* torsocks.h - Structures used by torsocks to form SOCKS requests */
-
-#ifndef _TORSOCKS_H
-
-#define _TORSOCKS_H 1
-
-#include "parser.h"
-
-/* Structure representing a socks connection request */
-struct sockreq {
- int8_t version;
- int8_t command;
- int16_t dstport;
- int32_t dstip;
- /* A null terminated username goes here */
-};
-
-/* Structure representing a socks connection request response */
-struct sockrep {
- int8_t version;
- int8_t result;
- int16_t ignore1;
- int32_t ignore2;
-};
-
-/* Structure representing a socket which we are currently proxying */
-struct connreq {
- /* Information about the socket and target */
- int sockid;
- struct sockaddr_in connaddr;
- struct sockaddr_in serveraddr;
-
- /* Pointer to the config entry for the socks server */
- struct serverent *path;
-
- /* Current state of this proxied socket */
- int state;
-
- /* Next state to go to when the send or receive is finished */
- int nextstate;
-
- /* When connections fail but an error number cannot be reported
- * because the socket is non blocking we keep the connreq struct until
- * the status is queried with connect() again, we then return
- * this value */
- int err;
-
- /* Events that were set for this socket upon call to select() or
- * poll() */
- int selectevents;
-
- /* Buffer for sending and receiving on the socket */
- unsigned int datalen;
- unsigned int datadone;
- char buffer[2048];
-
- struct connreq *next;
-};
-
-/* Connection statuses */
-#define UNSTARTED 0
-#define CONNECTING 1
-#define CONNECTED 2
-#define SENDING 3
-#define RECEIVING 4
-#define SENTV4REQ 5
-#define GOTV4REQ 6
-#define SENTV5METHOD 7
-#define GOTV5METHOD 8
-#define SENTV5AUTH 9
-#define GOTV5AUTH 10
-#define SENTV5CONNECT 11
-#define GOTV5CONNECT 12
-#define DONE 13
-#define FAILED 14
-
-/* Flags to indicate what events a socket was select()ed for */
-#define READ (1<<0)
-#define WRITE (1<<1)
-#define EXCEPT (1<<2)
-#define READWRITE (READ|WRITE)
-#define READWRITEEXCEPT (READ|WRITE|EXCEPT)
-
-#endif
More information about the tor-commits
mailing list