[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [torsocks/master] Move source code to old source directory
commit 36194ee1b1a6b979fcf7df49a1347d7b53130645
Author: David Goulet <dgoulet@xxxxxxxxx>
Date: Sun Jun 2 12:58:25 2013 -0400
Move source code to old source directory
Signed-off-by: David Goulet <dgoulet@xxxxxxxxx>
---
src.old/Makefile.am | 18 +
src.old/common.c | 224 +++++++++
src.old/common.h | 104 +++++
src.old/darwin_warts.c | 59 +++
src.old/dead_pool.c | 805 ++++++++++++++++++++++++++++++++
src.old/dead_pool.h | 67 +++
src.old/expansion_table.h | 125 +++++
src.old/parser.c | 872 +++++++++++++++++++++++++++++++++++
src.old/parser.h | 69 +++
src.old/socks.c | 633 ++++++++++++++++++++++++++
src.old/socks.h | 116 +++++
src.old/torsocks.c | 1108 +++++++++++++++++++++++++++++++++++++++++++++
src.old/torsocks.in | 167 +++++++
src.old/usewithtor.in | 113 +++++
src/common.c | 224 ---------
src/common.h | 104 -----
src/darwin_warts.c | 59 ---
src/dead_pool.c | 805 --------------------------------
src/dead_pool.h | 67 ---
src/expansion_table.h | 125 -----
src/parser.c | 872 -----------------------------------
src/parser.h | 69 ---
src/socks.c | 633 --------------------------
src/socks.h | 116 -----
src/torsocks.c | 1108 ---------------------------------------------
src/torsocks.in | 167 -------
src/usewithtor.in | 113 -----
27 files changed, 4480 insertions(+), 4462 deletions(-)
diff --git a/src.old/Makefile.am b/src.old/Makefile.am
new file mode 100644
index 0000000..e3a01c9
--- /dev/null
+++ b/src.old/Makefile.am
@@ -0,0 +1,18 @@
+# Makefile used by configure to create real Makefile
+
+libdir = @libdir@/torsocks
+
+# Install invocation scripts
+bin_SCRIPTS = torsocks usewithtor
+INSTALL_SCRIPT = $(install_sh) -c -m 755
+
+libtorsocks_la_LDFLAGS= $(TORSOCKSLDFLAGS)
+# 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 socks.c\
+ common.h dead_pool.h expansion_table.h parser.h socks.h
+
+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.old/common.c b/src.old/common.c
new file mode 100644
index 0000000..8fe3303
--- /dev/null
+++ b/src.old/common.c
@@ -0,0 +1,224 @@
+/***************************************************************************
+ * *
+ * Copyright (C) 2000-2008 Shaun Clowes <delius@xxxxxxxxxxx> *
+ * Copyright (C) 2008-2011 Robert Hogan <robert@xxxxxxxxxxxxxxx> *
+ * *
+ * 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. *
+ * *
+ * Some code taken from Tor: *
+ * Copyright (c) 2003, Roger Dingledine *
+ * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. *
+ * Copyright (c) 2007-2008, The Tor Project, Inc. *
+ * *
+ ***************************************************************************/
+/*
+
+ commmon.c - Common routines for the torsocks package
+
+*/
+
+#include <config.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#include "common.h"
+
+/* Globals */
+int loglevel = MSGERR; /* The default logging level is to only log
+ error messages */
+char logfilename[256]; /* Name of file to which log messages should
+ be redirected */
+FILE *logfile = NULL; /* File to which messages should be logged */
+int logstamp = 0; /* Timestamp (and pid stamp) messages */
+
+
+/**
+ * Read a 16-bit value beginning at <b>cp</b>. Equivalent to
+ * *(uint16_t*)(cp), but will not cause segfaults on platforms that forbid
+ * unaligned memory access.
+ */
+uint16_t
+get_uint16(const char *cp)
+{
+ uint16_t v;
+ memcpy(&v,cp,2);
+ return v;
+}
+/**
+ * Read a 32-bit value beginning at <b>cp</b>. Equivalent to
+ * *(uint32_t*)(cp), but will not cause segfaults on platforms that forbid
+ * unaligned memory access.
+ */
+uint32_t
+get_uint32(const char *cp)
+{
+ uint32_t v;
+ memcpy(&v,cp,4);
+ return v;
+}
+/**
+ * Set a 16-bit value beginning at <b>cp</b> to <b>v</b>. Equivalent to
+ * *(uint16_t)(cp) = v, but will not cause segfaults on platforms that forbid
+ * unaligned memory access. */
+void
+set_uint16(char *cp, uint16_t v)
+{
+ memcpy(cp,&v,2);
+}
+/**
+ * Set a 32-bit value beginning at <b>cp</b> to <b>v</b>. Equivalent to
+ * *(uint32_t)(cp) = v, but will not cause segfaults on platforms that forbid
+ * unaligned memory access. */
+void
+set_uint32(char *cp, uint32_t v)
+{
+ memcpy(cp,&v,4);
+}
+
+unsigned int resolve_ip(char *host, int showmsg, int allownames) {
+ struct hostent *new;
+ unsigned int hostaddr;
+ struct in_addr *ip;
+
+ if ((hostaddr = inet_addr(host)) == (unsigned int) -1) {
+ /* We couldn't convert it as a numerical ip so */
+ /* try it as a dns name */
+ if (allownames) {
+ #ifdef HAVE_GETHOSTBYNAME
+ if ((new = gethostbyname(host)) == (struct hostent *) 0) {
+ #endif
+ return(0);
+ #ifdef HAVE_GETHOSTBYNAME
+ } else {
+ ip = ((struct in_addr *) * new->h_addr_list);
+ hostaddr = ip -> s_addr;
+ if (showmsg)
+ printf("Connecting to %s...\n", inet_ntoa(*ip));
+ }
+ #endif
+ } else
+ return(0);
+ }
+
+ return (hostaddr);
+}
+
+/* Set logging options, the options are as follows: */
+/* level - This sets the logging threshold, messages with */
+/* a higher level (i.e lower importance) will not be */
+/* output. For example, if the threshold is set to */
+/* MSGWARN a call to log a message of level MSGDEBUG */
+/* would be ignored. This can be set to -1 to disable */
+/* messages entirely */
+/* filename - This is a filename to which the messages should */
+/* be logged instead of to standard error */
+/* timestamp - This indicates that messages should be prefixed */
+/* with timestamps (and the process id) */
+void set_log_options(int level, char *filename, int timestamp) {
+
+ loglevel = level;
+ if (loglevel < MSGERR)
+ loglevel = MSGNONE;
+
+ if (filename) {
+ strncpy(logfilename, filename, sizeof(logfilename));
+ logfilename[sizeof(logfilename) - 1] = '\0';
+ }
+
+ logstamp = timestamp;
+}
+
+/* Count the bits in a netmask. This is a little bit buggy; it assumes
+ all the zeroes are on the right... */
+
+int count_netmask_bits(uint32_t mask)
+{
+ int i;
+ int nbits = 0;
+
+ for(i=0; i<32; i++) {
+ if((mask >> i) & 1) {
+ nbits++;
+ }
+ }
+ mask = ~mask;
+ mask = ntohl(mask);
+ if(mask & (mask+1)) {
+ return -1; /* Noncontiguous */
+ }
+ return nbits;
+}
+
+void show_msg(int level, const char *fmt, ...) {
+ va_list ap;
+ int saveerr;
+ extern char *torsocks_progname;
+ char timestring[20];
+ time_t timestamp;
+
+ if ((loglevel == MSGNONE) || (level > loglevel))
+ return;
+
+ if (!logfile) {
+ if (logfilename[0]) {
+ logfile = fopen(logfilename, "a");
+ if (logfile == NULL) {
+ logfile = stderr;
+ show_msg(MSGERR, "Could not open log file, %s, %s\n",
+ logfilename, strerror(errno));
+ }
+ } else
+ logfile = stderr;
+ }
+
+ if (logstamp) {
+ timestamp = time(NULL);
+ strftime(timestring, sizeof(timestring), "%H:%M:%S",
+ localtime(×tamp));
+ fprintf(logfile, "%s ", timestring);
+ }
+
+ fputs(torsocks_progname, logfile);
+
+ if (logstamp) {
+ fprintf(logfile, "(%d)", getpid());
+ }
+
+ fputs(": ", logfile);
+
+ va_start(ap, fmt);
+
+ /* Save errno */
+ saveerr = errno;
+
+ vfprintf(logfile, fmt, ap);
+
+ fflush(logfile);
+
+ errno = saveerr;
+
+ va_end(ap);
+}
+
diff --git a/src.old/common.h b/src.old/common.h
new file mode 100644
index 0000000..f84a2f7
--- /dev/null
+++ b/src.old/common.h
@@ -0,0 +1,104 @@
+/***************************************************************************
+ * *
+ * Copyright (C) 2000-2008 Shaun Clowes <delius@xxxxxxxxxxx> *
+ * Copyright (C) 2008-2011 Robert Hogan <robert@xxxxxxxxxxxxxxx> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+/* Common functions provided in common.c */
+/* GCC has several useful attributes. */
+#include <sys/types.h>
+
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define ATTR_NORETURN __attribute__((noreturn))
+#define ATTR_PURE __attribute__((pure))
+#define ATTR_CONST __attribute__((const))
+#define ATTR_MALLOC __attribute__((malloc))
+#define ATTR_NORETURN __attribute__((noreturn))
+#define ATTR_NONNULL(x) __attribute__((nonnull x))
+/** Macro: Evaluates to <b>exp</b> and hints the compiler that the value
+ * of <b>exp</b> will probably be true. */
+#define PREDICT_LIKELY(exp) __builtin_expect((exp), 1)
+/** Macro: Evaluates to <b>exp</b> and hints the compiler that the value
+ * of <b>exp</b> will probably be false. */
+#define PREDICT_UNLIKELY(exp) __builtin_expect((exp), 0)
+#else
+#define ATTR_NORETURN
+#define ATTR_PURE
+#define ATTR_CONST
+#define ATTR_MALLOC
+#define ATTR_NORETURN
+#define ATTR_NONNULL(x)
+#define PREDICT_LIKELY(exp) (exp)
+#define PREDICT_UNLIKELY(exp) (exp)
+#endif
+
+/** Try to find the symbol that is either m or __m.
+ * If one of them exists, in that order, then save its address in r,
+ * otherwise we want to print a message at log level l stating that
+ * we could not find it.
+ */
+#define torsocks_find_library(m,l,r) \
+ do { \
+ char * dl_error_msg = ""; \
+ char * dl_error_msg2 = ""; \
+ dlerror(); \
+ if ((r = dlsym(RTLD_NEXT, m)) == NULL) { \
+ dl_error_msg = dlerror(); \
+ if (dl_error_msg != NULL) { \
+ dl_error_msg = strdup(dl_error_msg); \
+ } \
+ if ((r = dlsym(RTLD_NEXT, "__" m)) == NULL) { \
+ dl_error_msg2 = dlerror(); \
+ show_msg(l, "WARNING: The symbol %s() was not found in any shared " \
+ "library with the reported error: %s!\n" \
+ " Also, we failed to find the symbol %s() with the reported error:" \
+ " %s\n", m, (dl_error_msg ? dl_error_msg : "Not Found"), \
+ "__"m, (dl_error_msg2 ? dl_error_msg2 : "Not Found")); \
+ } \
+ if (dl_error_msg) \
+ free(dl_error_msg); \
+ } \
+ } while (0)
+
+uint16_t get_uint16(const char *cp) ATTR_PURE ATTR_NONNULL((1));
+uint32_t get_uint32(const char *cp) ATTR_PURE ATTR_NONNULL((1));
+void set_uint16(char *cp, uint16_t v) ATTR_NONNULL((1));
+void set_uint32(char *cp, uint32_t v) ATTR_NONNULL((1));
+
+int is_internal_IP(uint32_t ip, int for_listening) ATTR_PURE;
+int parse_addr_port(int severity, const char *addrport, char **address,
+ uint32_t *addr, uint16_t *port_out);
+
+void set_log_options(int, char *, int);
+void show_msg(int level, const char *, ...);
+int count_netmask_bits(uint32_t mask);
+unsigned int resolve_ip(char *, int, int);
+
+#define MSGNONE -1
+#define MSGERR 0
+#define MSGWARN 1
+#define MSGTEST 2
+#define MSGNOTICE 3
+#define MSGDEBUG 3
+
+/* Required by some BSDs */
+#ifndef MAP_ANONYMOUS
+#ifdef MAP_ANON
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+#endif
diff --git a/src.old/darwin_warts.c b/src.old/darwin_warts.c
new file mode 100644
index 0000000..65bdd04
--- /dev/null
+++ b/src.old/darwin_warts.c
@@ -0,0 +1,59 @@
+/***************************************************************************
+ * *
+ * Copyright (C) 2010 Alex Rosenberg <alex@xxxxxxxxxxxxx> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+/* Mac OS X 10.6 forces any function named "select" to be named "_select$1050"
+ * in the output to the assembler. We need to patch select as well, so this
+ * isolated code exists without tripping over the Darwin header that causes the
+ * probkem.
+ */
+
+#if defined(__APPLE__) || defined(__darwin__)
+
+#include <AvailabilityMacros.h>
+
+#if defined(MAC_OS_X_VERSION_10_6)
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <string.h>
+#include <errno.h>
+#include "common.h"
+
+#define SELECT_SIGNATURE int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout
+#define SELECT_ARGNAMES n, readfds, writefds, exceptfds, timeout
+
+/* forward declare opaque structures instead of bringing in real Darwin decls. */
+typedef struct fd_set fd_set;
+struct timeval;
+
+int (*realselect)(SELECT_SIGNATURE);
+int torsocks_select_guts(SELECT_SIGNATURE, int (*original_select)(SELECT_SIGNATURE));
+
+int select(SELECT_SIGNATURE) {
+ if (!realselect) {
+ torsocks_find_library("select", MSGERR, realselect);
+ }
+ return torsocks_select_guts(SELECT_ARGNAMES, realselect);
+}
+
+#endif /* 10.6 */
+#endif /* darwin */
diff --git a/src.old/dead_pool.c b/src.old/dead_pool.c
new file mode 100644
index 0000000..13e5740
--- /dev/null
+++ b/src.old/dead_pool.c
@@ -0,0 +1,805 @@
+/***************************************************************************
+ * *
+ * Copyright (C) 2005 Total Information Security Ltd. *
+ * Copyright (C) 2008-2011 Robert Hogan <robert@xxxxxxxxxxxxxxx> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+
+#include "common.h"
+#include "dead_pool.h"
+
+int store_pool_entry(dead_pool *pool, char *hostname, struct in_addr *addr);
+void get_next_dead_address(dead_pool *pool, uint32_t *result);
+
+static int
+do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport,
+ uint32_t *result_addr, const void *addr,
+ int version, int reverse, char **result_hostname);
+
+/* Compares the last strlen(s2) characters of s1 with s2. Returns as for
+ strcasecmp. */
+static int
+strcasecmpend(const char *s1, const char *s2)
+{
+ size_t n1 = strlen(s1), n2 = strlen(s2);
+ if (n2>n1) /* then they can't be the same; figure out which is bigger */
+ return strcasecmp(s1,s2);
+ else
+ return strncasecmp(s1+(n1-n2), s2, n2);
+}
+
+dead_pool *
+init_pool(unsigned int pool_size, struct in_addr deadrange_base,
+ struct in_addr deadrange_mask, char *sockshost, uint16_t socksport)
+{
+ unsigned int i, deadrange_size, deadrange_width;
+ int deadrange_bits;
+ struct in_addr socks_server;
+ dead_pool *newpool = NULL;
+
+ /* Count bits in netmask and determine deadrange width. */
+ deadrange_bits = count_netmask_bits(deadrange_mask.s_addr);
+ if(deadrange_bits == -1) {
+ show_msg(MSGERR, "init_pool: invalid netmask for deadrange\n");
+ return NULL;
+ }
+ deadrange_width = 32 - deadrange_bits;
+
+ show_msg(MSGDEBUG, "deadrange width is %d bits\n", deadrange_width);
+
+ /* Now work out how many IPs are available in the deadrange and check
+ that this number makes sense. If the deadpool is bigger than the
+ deadrange we shrink the pool. */
+
+ for(i=0, deadrange_size = 1; i < deadrange_width; i++) {
+ deadrange_size *= 2;
+ }
+
+ if(deadrange_size < pool_size) {
+ show_msg(MSGWARN, "tordns cache size was %d, but deadrange size is %d: "
+ "shrinking pool size to %d entries\n", pool_size,
+ deadrange_size, deadrange_size);
+ pool_size = deadrange_size;
+ }
+ if(pool_size < 1) {
+ show_msg(MSGERR, "tordns cache size is 0, disabling tordns\n");
+ return NULL;
+ }
+
+ /* Allocate space for the dead_pool structure */
+ newpool = (dead_pool *) mmap(0, sizeof(dead_pool),
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ if(!newpool) {
+ show_msg(MSGERR, "init_pool: unable to mmap deadpool "
+ "(tried to map %d bytes)\n", sizeof(dead_pool));
+ return NULL;
+ }
+
+ show_msg(MSGDEBUG, "init_pool: sockshost %s \n", sockshost);
+
+ /* Initialize the dead_pool structure */
+#ifdef HAVE_INET_ATON
+ inet_aton(sockshost, &socks_server);
+#elif defined(HAVE_INET_ADDR)
+ socks_server.s_addr = inet_addr(sockshost);
+#endif
+ newpool->sockshost = ntohl(socks_server.s_addr);
+ newpool->socksport = socksport;
+ newpool->deadrange_base = ntohl(deadrange_base.s_addr);
+ newpool->deadrange_mask = ntohl(deadrange_mask.s_addr);
+ newpool->deadrange_size = deadrange_size;
+ newpool->write_pos = 0;
+ newpool->dead_pos = 0;
+ newpool->n_entries = pool_size;
+
+ /* Allocate space for the entries */
+ newpool->entries = (pool_ent *) mmap(0, newpool->n_entries * sizeof(pool_ent),
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ if(!newpool->entries) {
+ munmap((void *)newpool, sizeof(dead_pool));
+ show_msg(MSGERR, "init_pool: unable to mmap deadpool entries "
+ "(tried to map %d bytes)\n",
+ newpool->n_entries * sizeof(pool_ent));
+ return NULL;
+ }
+
+ /* Initialize the entries */
+ for(i=0; i < newpool->n_entries; i++) {
+ newpool->entries[i].ip = -1;
+ newpool->entries[i].name[0] = '\0';
+ }
+
+ return newpool;
+}
+
+int
+is_dead_address(dead_pool *pool, uint32_t addr)
+{
+ uint32_t haddr = ntohl(addr);
+ if(pool == NULL) {
+ return 0;
+ }
+ return (pool->deadrange_base == (haddr & pool->deadrange_mask));
+}
+
+void
+get_next_dead_address(dead_pool *pool, uint32_t *result)
+{
+ *result = htonl(pool->deadrange_base + pool->dead_pos++);
+ if(pool->dead_pos >= pool->deadrange_size) {
+ pool->dead_pos = 0;
+ }
+}
+
+int
+store_pool_entry(dead_pool *pool, char *hostname, struct in_addr *addr)
+{
+ int position = pool->write_pos;
+ int oldpos;
+ int rc;
+ uint32_t intaddr;
+ char *result_hostname;
+
+ show_msg(MSGDEBUG, "store_pool_entry: storing '%s'\n", hostname);
+ show_msg(MSGDEBUG, "store_pool_entry: write pos is: %d\n", pool->write_pos);
+
+ /* Check to see if name already exists in pool */
+ oldpos = search_pool_for_name(pool, hostname);
+ if(oldpos != -1){
+ show_msg(MSGDEBUG, "store_pool_entry: not storing (entry exists)\n");
+ addr->s_addr = pool->entries[oldpos].ip;
+ return oldpos;
+ }
+
+ /* If this is a .onion host, then we return a bogus ip from our deadpool,
+ otherwise we try to resolve it and store the 'real' IP */
+ if(strcasecmpend(hostname, ".onion") == 0) {
+ get_next_dead_address(pool, &pool->entries[position].ip);
+ } else {
+ rc = do_resolve(hostname, pool->sockshost, pool->socksport, &intaddr, 0,
+ 4 /*SOCKS5*/, 0 /*Reverse*/, &result_hostname);
+
+ if(rc != 0) {
+ show_msg(MSGWARN, "failed to resolve: %s\n", hostname);
+ return -1;
+ }
+ if(is_dead_address(pool, intaddr)) {
+ show_msg(MSGERR, "resolved %s -> %d (deadpool address) IGNORED\n");
+ return -1;
+ }
+ pool->entries[position].ip = intaddr;
+ }
+
+ strncpy(pool->entries[position].name, hostname, 255);
+ pool->entries[position].name[255] = '\0';
+ pool->write_pos++;
+ if(pool->write_pos >= pool->n_entries) {
+ pool->write_pos = 0;
+ }
+ addr->s_addr = pool->entries[position].ip;
+
+ show_msg(MSGDEBUG, "store_pool_entry: stored entry in slot '%d'\n", position);
+
+ return position;
+}
+
+int
+search_pool_for_name(dead_pool *pool, const char *name)
+{
+ unsigned int i;
+ for(i=0; i < pool->n_entries; i++){
+ if(strcmp(name, pool->entries[i].name) == 0){
+ return i;
+ }
+ }
+ return -1;
+}
+
+char *
+get_pool_entry(dead_pool *pool, struct in_addr *addr)
+{
+ unsigned int i;
+ uint32_t intaddr = addr->s_addr;
+
+ if(pool == NULL) {
+ return NULL;
+ }
+
+ show_msg(MSGDEBUG, "get_pool_entry: searching for: %s\n", inet_ntoa(*addr));
+ for(i=0; i<pool->n_entries; i++) {
+ if(intaddr == pool->entries[i].ip) {
+ show_msg(MSGDEBUG, "get_pool_entry: found: %s\n", pool->entries[i].name);
+ return pool->entries[i].name;
+ }
+ }
+ show_msg(MSGDEBUG, "get_pool_entry: address not found\n");
+
+ return NULL;
+}
+
+static int
+build_socks4a_resolve_request(char **out,
+ const char *username,
+ const char *hostname)
+{
+ size_t len;
+ uint16_t port = htons(0); /* port: 0. */
+ uint32_t addr = htonl(0x00000001u); /* addr: 0.0.0.1 */
+
+ len = 8 + strlen(username) + 1 + strlen(hostname) + 1;
+ *out = malloc(len);
+ (*out)[0] = 4; /* SOCKS version 4 */
+ (*out)[1] = '\xF0'; /* Command: resolve. */
+
+ memcpy((*out)+2, &port, sizeof(port));
+ memcpy((*out)+4, &addr, sizeof(addr));
+ strcpy((*out)+8, username);
+ strcpy((*out)+8+strlen(username)+1, hostname);
+
+ return len;
+}
+
+static int
+build_socks5_resolve_ptr_request(char **out, const void *_addr)
+{
+ size_t len;
+ const struct in_addr *addr=_addr;
+
+ len = 12;
+ *out = malloc(len);
+ (*out)[0] = 5; /* SOCKS version 5 */
+ (*out)[1] = '\xF1'; /* Command: reverse resolve.
+ see doc/socks-extensions.txt*/
+ (*out)[2] = '\x00'; /* RSV */
+ (*out)[3] = '\x01'; /* ATYP: IP V4 address: X'01' */
+
+ set_uint32((*out)+4, addr->s_addr);/*IP*/
+ set_uint16((*out)+4+4, 0); /* port */
+
+ return len;
+}
+
+#define RESPONSE_LEN 8
+#define SOCKS5_LEN 4
+#define METHODRESPONSE_LEN 2
+
+static int
+parse_socks4a_resolve_response(const char *response, size_t len,
+ uint32_t *addr_out)
+{
+ uint8_t status;
+ uint16_t port;
+
+ if (len < RESPONSE_LEN) {
+ show_msg(MSGWARN,"Truncated socks response.\n");
+ return -1;
+ }
+ if (((uint8_t)response[0])!=0) { /* version: 0 */
+ show_msg(MSGWARN,"Nonzero version in socks response: bad format.\n");
+ return -1;
+ }
+ status = (uint8_t)response[1];
+
+ memcpy(&port, response+2, sizeof(port));
+ if (port!=0) { /* port: 0 */
+ show_msg(MSGWARN,"Nonzero port in socks response: bad format.\n");
+ return -1;
+ }
+ if (status != 90) {
+ show_msg(MSGWARN,"Bad status: socks request failed.\n");
+ return -1;
+ }
+
+ memcpy(addr_out, response+4, sizeof(*addr_out));
+
+ return 0;
+}
+
+static int
+parse_socks5_resolve_ptr_response(int s,const char *response, size_t len,
+ uint32_t *result_addr, char ***result_hostname)
+{
+ char reply_buf[4];
+ int r;
+
+ len=0;
+ while (len < SOCKS5_LEN) {
+ r = recv(s, reply_buf+len, SOCKS5_LEN-len, 0);
+ if (r==0) {
+ show_msg(MSGWARN, "do_resolve: EOF while reading SOCKS5 response\n");
+ return -1;
+ }
+ if (r<0) {
+ show_msg(MSGWARN, "do_resolve: error reading SOCKS5 response\n");
+ return -1;
+ }
+ len += r;
+ }
+
+ if (reply_buf[0] != 5) {
+ show_msg(MSGWARN, "Bad SOCKS5 reply version.");
+ return -1;
+ }
+ if (reply_buf[1] != 0) {
+ show_msg(MSGWARN,"Got status response '%u': SOCKS5 request failed.",
+ (unsigned)reply_buf[1]);
+ return -1;
+ }
+ if (reply_buf[3] == 1) {
+ /* IPv4 address */
+ len=0;
+ while (len < SOCKS5_LEN) {
+ r = recv(s, reply_buf+len, SOCKS5_LEN-len, 0);
+ if (r==0) {
+ show_msg(MSGWARN, "do_resolve: EOF while reading SOCKS5 response\n");
+ return -1;
+ }
+ if (r<0) {
+ show_msg(MSGWARN, "do_resolve: error reading address in SOCKS5 response\n");
+ return -1;
+ }
+ len += r;
+ }
+ *result_addr = ntohl(get_uint32(reply_buf));
+ } else if (reply_buf[3] == 3) {
+ size_t result_len;
+ len=0;
+ while (len < 1) {
+ r = recv(s, reply_buf+len, 1-len, 0);
+ if (r==0) {
+ show_msg(MSGWARN, "do_resolve: EOF while reading SOCKS5 response\n");
+ return -1;
+ }
+ if (r<0) {
+ show_msg(MSGWARN, "do_resolve: error reading address length in SOCKS5 response\n");
+ return -1;
+ }
+ len += r;
+ }
+ result_len = *(uint8_t*)(reply_buf);
+ **result_hostname = malloc(result_len+1);
+ len=0;
+ while (len < (int) result_len) {
+ r = recv(s, **result_hostname+len, result_len-len, 0);
+ if (r==0) {
+ show_msg(MSGWARN, "do_resolve: EOF while reading SOCKS5 response\n");
+ return -1;
+ }
+ if (r<0) {
+ show_msg(MSGWARN, "do_resolve: error reading hostname in SOCKS5 response\n");
+ return -1;
+ }
+ len += r;
+ }
+
+ (**result_hostname)[result_len] = '\0';
+ }
+
+ return 0;
+}
+
+static int
+do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport,
+ uint32_t *result_addr, const void *addr,
+ int version, int reverse, char **result_hostname)
+{
+ int s;
+ struct sockaddr_in socksaddr;
+ char *req, *cp=NULL;
+ int r, len, hslen;
+ char response_buf[RESPONSE_LEN];
+ const char *handshake="\x05\x01\x00";
+
+ show_msg(MSGDEBUG, "do_resolve: resolving %s\n", hostname);
+
+ /* Create SOCKS connection */
+ s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (s<0) {
+ show_msg(MSGWARN, "do_resolve: problem creating socket\n");
+ return -1;
+ }
+
+ /* Connect to SOCKS server */
+ memset(&socksaddr, 0, sizeof(socksaddr));
+ socksaddr.sin_family = AF_INET;
+ socksaddr.sin_port = htons(socksport);
+ socksaddr.sin_addr.s_addr = htonl(sockshost);
+ if (realconnect(s, (struct sockaddr*)&socksaddr, sizeof(socksaddr))) {
+ show_msg(MSGWARN, "do_resolve: error connecting to SOCKS server\n");
+ realclose(s);
+ return -1;
+ }
+
+ /* If a SOCKS5 connection, perform handshake */
+ if (version == 5) {
+ char method_buf[2];
+ hslen=3;
+ while (hslen) {
+ r = send(s, handshake, hslen, 0);
+ if (r<0) {
+ show_msg(MSGWARN, "do_resolve: error sending SOCKS5 method list.\n");
+ realclose(s);
+ return -1;
+ }
+ hslen -= r;
+ handshake += r;
+ }
+
+ len = 0;
+ while (len < METHODRESPONSE_LEN) {
+ r = recv(s, method_buf+len, METHODRESPONSE_LEN-len, 0);
+ if (r==0) {
+ show_msg(MSGWARN, "do_resolve: EOF while reading SOCKS response\n");
+ realclose(s);
+ return -1;
+ }
+ if (r<0) {
+ show_msg(MSGWARN, "do_resolve: error reading SOCKS response\n");
+ realclose(s);
+ return -1;
+ }
+ len += r;
+ }
+
+ if (method_buf[0] != '\x05') {
+ show_msg(MSGWARN, "Unrecognized socks version: %u",
+ (unsigned)method_buf[0]);
+ realclose(s);
+ return -1;
+ }
+ if (method_buf[1] != '\x00') {
+ show_msg(MSGWARN, "Unrecognized socks authentication method: %u",
+ (unsigned)method_buf[1]);
+ realclose(s);
+ return -1;
+ }
+ }
+
+ /* Create SOCKS request */
+ if (reverse) {
+ if ((len = build_socks5_resolve_ptr_request(&req, addr))<0) {
+ show_msg(MSGWARN, "do_resolve: error generating reverse SOCKS request\n");
+ realclose(s);
+ return -1;
+ }
+ }else{
+ if ((len = build_socks4a_resolve_request(&req, "", hostname))<0) {
+ show_msg(MSGWARN, "do_resolve: error generating SOCKS request\n");
+ realclose(s);
+ return -1;
+ }
+ }
+
+ /* Send SOCKS request */
+ cp = req;
+ while (len) {
+ r = send(s, cp, len, 0);
+ if (r<0) {
+ show_msg(MSGWARN, "do_resolve: error sending SOCKS request\n");
+ free(req);
+ realclose(s);
+ return -1;
+ }
+ len -= r;
+ cp += r;
+ }
+ free(req);
+
+ /* Handle SOCKS Response */
+ if (reverse) {
+ if (parse_socks5_resolve_ptr_response(s, response_buf, RESPONSE_LEN,
+ result_addr, &result_hostname) < 0){
+ show_msg(MSGWARN, "do_resolve: error parsing SOCKS response\n");
+ realclose(s);
+ return -1;
+ }
+ }else{
+ /* Process SOCKS response */
+ len = 0;
+ while (len < RESPONSE_LEN) {
+ r = recv(s, response_buf+len, RESPONSE_LEN-len, 0);
+ if (r==0) {
+ show_msg(MSGWARN, "do_resolve: EOF while reading SOCKS response\n");
+ realclose(s);
+ return -1;
+ }
+ if (r<0) {
+ show_msg(MSGWARN, "do_resolve: error reading SOCKS response\n");
+ realclose(s);
+ return -1;
+ }
+ len += r;
+ }
+ realclose(s);
+
+ /* Parse SOCKS response */
+ if (parse_socks4a_resolve_response(response_buf, RESPONSE_LEN, result_addr) < 0){
+ show_msg(MSGWARN, "do_resolve: error parsing SOCKS response\n");
+ return -1;
+ }
+ }
+
+
+ show_msg(MSGDEBUG, "do_resolve: success\n");
+
+ return 0;
+}
+
+struct hostent *
+our_gethostbyaddr(dead_pool *pool, const void *_addr, socklen_t len, int type)
+{
+ const struct in_addr *addr=_addr;
+ static struct hostent he;
+ uint32_t intaddr=0;
+ char *result_hostname=NULL;
+ int rc=0;
+ static char *addrs[2];
+ static char *aliases[2];
+
+ rc = do_resolve("", pool->sockshost, pool->socksport, &intaddr, addr,
+ 5 /*SOCKS5*/, 1 /*Reverse*/, &result_hostname);
+
+
+ if(rc != 0) {
+ show_msg(MSGWARN, "failed to reverse resolve: %s\n",
+ inet_ntoa(*((struct in_addr *)addr)));
+ result_hostname=NULL;
+ addrs[0] = NULL;
+ addrs[1] = NULL;
+ }else{
+ addrs[0] = (char *)addr;
+ addrs[1] = NULL;
+ }
+
+ if (result_hostname)
+ he.h_name = result_hostname;
+ else
+ he.h_name = inet_ntoa(*((struct in_addr *)addr));
+
+ aliases[0] = NULL;
+ aliases[1] = NULL;
+
+ he.h_aliases = aliases;
+ he.h_length = len;
+ he.h_addrtype = type;
+ he.h_addr_list = addrs;
+
+ if (result_hostname)
+ show_msg(MSGTEST, "our_gethostbyaddr: resolved '%s' to: '%s'\n",
+ inet_ntoa(*((struct in_addr *)he.h_addr)), result_hostname);
+
+ return &he;
+
+}
+
+struct hostent *
+our_gethostbyname(dead_pool *pool, const char *name)
+{
+ int pos;
+ static struct in_addr addr;
+ static struct hostent he;
+ static char *addrs[2];
+
+ show_msg(MSGTEST, "our_gethostbyname: '%s' requested\n", name);
+
+ pos = store_pool_entry(pool,(char *) name, &addr);
+ if(pos == -1) {
+ h_errno = HOST_NOT_FOUND;
+ return NULL;
+ }
+
+ addrs[0] = (char *)&addr;
+ addrs[1] = NULL;
+
+ he.h_name = pool->entries[pos].name;
+ he.h_aliases = NULL;
+ he.h_length = 4;
+ he.h_addrtype = AF_INET;
+ he.h_addr_list = addrs;
+
+ show_msg(MSGDEBUG, "our_gethostbyname: resolved '%s' to: '%s'\n",
+ name, inet_ntoa(*((struct in_addr *)he.h_addr)));
+
+ return &he;
+}
+
+static struct hostent *
+alloc_hostent(int af)
+{
+ struct hostent *he = NULL;
+ char **addr_list = NULL;
+ void *addr = NULL;
+ char **aliases = NULL;
+
+ if(af != AF_INET && af != AF_INET6) {
+ return NULL;
+ }
+
+ /* Since the memory we allocate here will be free'd by freehostent and
+ that function is opaque to us, it's likely that we'll leak a little
+ bit of memory here. */
+
+ he = malloc(sizeof(struct hostent));
+ addr_list = malloc(2 * sizeof(char *));
+ if(af == AF_INET6) {
+ addr = malloc(sizeof(struct in6_addr));
+ } else {
+ addr = malloc(sizeof(struct in_addr));
+ }
+ aliases = malloc(sizeof(char *));
+
+ if(he == NULL || addr_list == NULL || addr == NULL || aliases == NULL) {
+ if(he)
+ free(he);
+ if(addr_list)
+ free(addr_list);
+ if(addr)
+ free(addr);
+ if(aliases)
+ free(aliases);
+ }
+
+ he->h_name = NULL;
+ he->h_addr_list = addr_list;
+ he->h_addr_list[0] = addr;
+ he->h_addr_list[1] = NULL;
+ he->h_aliases = aliases;
+ he->h_aliases[0] = NULL;
+ he->h_length = af == AF_INET ? 4 : 16;
+ he->h_addrtype = af;
+
+ return he;
+}
+
+/* On Linux, there's no freehostent() anymore; we might as well implement
+ this ourselves. */
+
+static void
+free_hostent(struct hostent *he)
+{
+ int i;
+ if(he->h_name) {
+ free(he->h_name);
+ }
+ if(he->h_aliases) {
+ for(i=0; he->h_aliases[i] != NULL; i++) {
+ free(he->h_aliases[i]);
+ }
+ free(he->h_aliases);
+ }
+ if(he->h_addr_list) {
+ free(he->h_addr_list);
+ }
+ free(he);
+}
+
+int
+our_getaddrinfo(dead_pool *pool, const char *node, const char *service,
+ void *hints, void *res)
+{
+ int pos;
+ struct in_addr addr;
+ char *ipstr;
+ int ret;
+
+ /* If "node" looks like a dotted-decimal ip address, then just call
+ the real getaddrinfo; otherwise we'll need to get an address from
+ our pool. */
+
+ /* TODO: work out what to do with AF_INET6 requests */
+
+#ifdef HAVE_INET_ATON
+ if(node && inet_aton(node, &addr) == 0 && memcmp(node,"*",1)) {
+#elif defined(HAVE_INET_ADDR)
+ /* If we're stuck with inet_addr, then getaddrinfo() won't work
+ properly with 255.255.255.255 (= -1). There's not much we can
+ do about this */
+ in_addr_t is_valid;
+ is_valid = inet_addr(node);
+ if(is_valid == -1) {
+#endif
+ pos = store_pool_entry(pool, (char *) node, &addr);
+ if(pos == -1) {
+ return EAI_NONAME;
+ } else {
+ ipstr = strdup(inet_ntoa(addr));
+ ret = realgetaddrinfo(ipstr, service, hints, res);
+ free(ipstr);
+ }
+ } else {
+ ret = realgetaddrinfo(node, service, hints, res);
+ }
+
+ show_msg(MSGTEST, "our_getaddrinfo: '%s' requested\n", service);
+ return ret;
+}
+
+struct hostent *
+our_getipnodebyname(dead_pool *pool, const char *name, int af, int flags,
+ int *error_num)
+{
+ int pos;
+ struct hostent *he = NULL;
+ int want_4in6 = 0;
+ char addr_convert_buf[80];
+ struct in_addr pool_addr;
+
+ if(af == AF_INET6) {
+ /* Caller has requested an AF_INET6 address, and is not prepared to
+ accept IPv4-mapped IPV6 addresses. There's nothing we can do to
+ service their request. */
+#ifdef OPENBSD
+ /* OpenBSD doesn't support the AI_V4MAPPED flag, so just return. */
+ return NULL;
+#else
+ if((flags & AI_V4MAPPED) == 0) {
+ show_msg(MSGWARN, "getipnodebyname: asked for V6 addresses only, "
+ "but torsocks can't handle that\n");
+ *error_num = NO_RECOVERY;
+ return NULL;
+ } else {
+ want_4in6 = 1;
+ }
+#endif
+ }
+
+ pos = store_pool_entry(pool, (char *)name, &pool_addr);
+ if(pos == -1) {
+ *error_num = HOST_NOT_FOUND;
+ return NULL;
+ }
+
+ he = alloc_hostent(af);
+ if(he == NULL) {
+ show_msg(MSGERR, "getipnodebyname: failed to allocate hostent\n");
+ *error_num = NO_RECOVERY;
+ return NULL;
+ }
+
+ if(want_4in6) {
+ /* Convert the ipv4 address in *addr to an IPv4 in IPv6 mapped
+ address. TODO: inet_ntoa() is thread-safe on Solaris but might
+ not be on other platforms. */
+ strcpy(addr_convert_buf, "::FFFF:");
+ strcpy(addr_convert_buf+7, inet_ntoa(pool_addr));
+ if(inet_pton(AF_INET6, addr_convert_buf, he->h_addr_list[0]) != 1) {
+ show_msg(MSGERR, "getipnodebyname: inet_pton() failed!\n");
+ free_hostent(he);
+ *error_num = NO_RECOVERY;
+ return NULL;
+ }
+ } else {
+ ((struct in_addr *) he->h_addr_list[0])->s_addr = pool_addr.s_addr;
+ }
+ he->h_name = strdup(name);
+
+ return he;
+}
+
+
diff --git a/src.old/dead_pool.h b/src.old/dead_pool.h
new file mode 100644
index 0000000..d6e3e10
--- /dev/null
+++ b/src.old/dead_pool.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+ * *
+ * Copyright (C) 2005 Total Information Security Ltd. *
+ * Copyright (C) 2008-2011 Robert Hogan <robert@xxxxxxxxxxxxxxx> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef _DEAD_POOL_H
+#define _DEAD_POOL_H
+
+#include <config.h>
+
+extern int (*realconnect)(CONNECT_SIGNATURE);
+extern int (*realclose)(CLOSE_SIGNATURE);
+extern int (*realgetaddrinfo)(GETADDRINFO_SIGNATURE);
+
+struct struct_pool_ent {
+ unsigned int ip;
+ char name[256];
+};
+
+typedef struct struct_pool_ent pool_ent;
+
+struct struct_dead_pool {
+ pool_ent *entries; /* Points to array of pool entries */
+ unsigned int n_entries; /* Number of entries in the deadpool */
+ unsigned int deadrange_base; /* Deadrange start IP in host byte order */
+ unsigned int deadrange_mask; /* Deadrange netmask in host byte order */
+ unsigned int deadrange_size; /* Number of IPs in the deadrange */
+ unsigned int write_pos; /* Next position to use in the pool array */
+ unsigned int dead_pos; /* Next 'unused' deadpool IP */
+ uint32_t sockshost;
+ uint16_t socksport;
+ char pad[2];
+};
+
+typedef struct struct_dead_pool dead_pool;
+
+dead_pool *init_pool(unsigned int deadpool_size, struct in_addr deadrange_base,
+ struct in_addr deadrange_mask, char *sockshost, uint16_t socksport);
+int is_dead_address(dead_pool *pool, uint32_t addr);
+char *get_pool_entry(dead_pool *pool, struct in_addr *addr);
+int search_pool_for_name(dead_pool *pool, const char *name);
+struct hostent *our_gethostbyname(dead_pool *pool, const char *name);
+struct hostent *our_gethostbyaddr(dead_pool *pool, const void *addr,
+ socklen_t len, int type);
+int our_getaddrinfo(dead_pool *pool, const char *node, const char *service,
+ void *hints, void *res);
+struct hostent *our_getipnodebyname(dead_pool *pool, const char *name,
+ int af, int flags, int *error_num);
+
+#endif /* _DEAD_POOL_H */
+
diff --git a/src.old/expansion_table.h b/src.old/expansion_table.h
new file mode 100644
index 0000000..14fabe1
--- /dev/null
+++ b/src.old/expansion_table.h
@@ -0,0 +1,125 @@
+/***************************************************************************
+ * *
+ * Copyright (C) 2010 Alex Rosenberg <alex@xxxxxxxxxxxxx> *
+ * Copyright (C) 2011 Robert Hogan <robert@xxxxxxxxxxxxxxx> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#undef FUNC
+#undef FUNCD
+#undef FUND32
+#undef FUNCD64
+
+#ifdef SUPPORT_RES_API
+#define RES_FUNC FUNC
+#define RES_FUNCD FUNCD
+#define RES_FUNCD32 FUNCD32
+#define RES_FUNCD64 FUNCD64
+#else
+#define RES_FUNC EMPTY_FUNC
+#define RES_FUNCD EMPTY_FUNC
+#define RES_FUNCD32 EMPTY_FUNC
+#define RES_FUNCD64 EMPTY_FUNC
+#endif /* SUPPORT_RES_API */
+
+#define DNS_FUNC FUNC
+#define DNS_FUNCD FUNCD
+#define DNS_FUNCD32 FUNCD32
+#define DNS_FUNCD64 FUNCD64
+
+#define EMPTY_FUNC(e,r,s,n,b,m)
+
+#if defined(__APPLE__) || defined(__darwin__)
+#ifndef DARWIN_EXPANSION
+#define DARWIN_EXPANSION PATCH_TABLE_EXPANSION
+#endif /* DARWIN_EXPANSION */
+#define FUNCD(e,r,s,n,b,m) DARWIN_EXPANSION(e,r,s,n,b,m)
+#if (__LP64__)
+#define FUNCD32(e,r,s,n,b,m) EMPTY_FUNC(e,r,s,n,b,m)
+#define FUNCD64(e,r,s,n,b,m) DARWIN_EXPANSION(e,r,s,n,b,m)
+/* This tests if we're building with 10.6 or later headers, not
+ if we're running on 10.6. We'd rather do the latter. */
+#ifdef MAC_OS_X_VERSION_10_6
+#define FUNCD64_106(e,r,s,n,b,m) DARWIN_EXPANSION(e,r,s,n,b,m)
+#else
+#define FUNCD64_106(e,r,s,n,b,m) EMPTY_FUNC(e,r,s,n,b,m)
+#endif /* MAC_OS_X_VERSION_10_6 */
+#else
+#define FUNCD32(e,r,s,n,b,m) DARWIN_EXPANSION(e,r,s,n,b,m)
+#define FUNCD64(e,r,s,n,b,m) EMPTY_FUNC(e,r,s,n,b,m)
+#define FUNCD64_106(e,r,s,n,b,m) EMPTY_FUNC(e,r,s,n,b,m)
+#endif /* (__LP64__) */
+#else
+#define FUNCD(e,r,s,n,b,m) EMPTY_FUNC(e,r,s,n,b,m)
+#define FUNCD32(e,r,s,n,b,m) EMPTY_FUNC(e,r,s,n,b,m)
+#define FUNCD64(e,r,s,n,b,m) EMPTY_FUNC(e,r,s,n,b,m)
+#define FUNCD64_106(e,r,s,n,b,m) EMPTY_FUNC(e,r,s,n,b,m)
+#endif /* defined(__APPLE__) || defined(__darwin__) */
+#define FUNC(e,r,s,n,b,m) PATCH_TABLE_EXPANSION(e,r,s,n,b,m)
+
+/* dlsym return type SIG/ARGS C name base name asm name */
+/* res_init takes void, so we do that one manually. */
+/*RES_FUNC (ERR, int, RES_INIT_, res_init, res_init, "res_init") */
+RES_FUNC (ERR, int, RES_QUERY_, res_query, res_query, "res_query")
+RES_FUNC (ERR, int, RES_SEARCH_, res_search, res_search, "res_search")
+RES_FUNC (ERR, int, RES_SEND_, res_send, res_send, "res_send")
+RES_FUNC (ERR, int, RES_QUERYDOMAIN_, res_querydomain, res_querydomain, "res_querydomain")
+
+DNS_FUNC (ERR, struct hostent *, GETHOSTBYNAME_, gethostbyname, gethostbyname, "gethostbyname")
+DNS_FUNC (ERR, struct hostent *, GETHOSTBYADDR_, gethostbyaddr, gethostbyaddr, "gethostbyaddr")
+DNS_FUNC (ERR, int, GETADDRINFO_, getaddrinfo, getaddrinfo, "getaddrinfo")
+/* getipnodebyname is deprecated so do not report an error if it is not available.*/
+DNS_FUNC (WARN, struct hostent *, GETIPNODEBYNAME_, getipnodebyname, getipnodebyname, "getipnodebyname")
+
+DNS_FUNC (ERR, ssize_t, SENDTO_, sendto, sendto, "sendto")
+DNS_FUNCD32 (ERR, ssize_t, SENDTO_, sendto_unix2003, sendto, "sendto$UNIX2003")
+DNS_FUNCD32 (ERR, ssize_t, SENDTO_, sendto_nocancel_unix2003, sendto, "sendto$NOCANCEL$UNIX2003")
+DNS_FUNCD64 (ERR, ssize_t, SENDTO_, sendto_nocancel, sendto, "sendto$NOCANCEL")
+
+DNS_FUNC (ERR, ssize_t, SENDMSG_, sendmsg, sendmsg, "sendmsg")
+DNS_FUNCD32 (ERR, ssize_t, SENDMSG_, sendmsg_unix2003, sendmsg, "sendmsg$UNIX2003")
+DNS_FUNCD32 (ERR, ssize_t, SENDMSG_, sendmsg_nocancel_unix2003, sendmsg, "sendmsg$NOCANCEL$UNIX2003")
+DNS_FUNCD64 (ERR, ssize_t, SENDMSG_, sendmsg_nocancel, sendmsg, "sendmsg$NOCANCEL")
+
+FUNC (ERR, int, CONNECT_, connect, connect, "connect")
+FUNCD32 (ERR, int, CONNECT_, connect_unix2003, connect, "connect$UNIX2003")
+FUNCD32 (ERR, int, CONNECT_, connect_nocancel_unix2003, connect, "connect$NOCANCEL$UNIX2003")
+FUNCD64 (ERR, int, CONNECT_, connect_nocancel, connect, "connect$NOCANCEL")
+
+#if !(defined(__APPLE__) || defined(__darwin__) && defined(MAX_OS_X_VERSION_10_6))
+/* see darwin_warts.c */
+FUNC (ERR, int, SELECT_, select, select, "select")
+#endif
+FUNCD (ERR, int, SELECT_, select_darwinextsn, select, "select$DARWIN_EXTSN")
+FUNCD (ERR, int, SELECT_, select_darwinextsn_nocancel, select, "select$DARWIN_EXTSN$NOCANCEL")
+FUNCD32 (ERR, int, SELECT_, select_unix2003, select, "select$UNIX2003")
+FUNCD32 (ERR, int, SELECT_, select_nocancel_unix2003, select, "select$NOCANCEL$UNIX2003")
+FUNCD64 (ERR, int, SELECT_, select_nocancel, select, "select$NOCANCEL")
+FUNCD64_106 (ERR, int, SELECT_, select_1050, select, "select$1050")
+
+FUNC (ERR, int, POLL_, poll, poll, "poll")
+FUNCD32 (ERR, int, POLL_, poll_unix2003, poll, "poll$UNIX2003")
+FUNCD32 (ERR, int, POLL_, poll_nocancel_unix2003, poll, "poll$NOCANCEL$UNIX2003")
+FUNCD64 (ERR, int, POLL_, poll_nocancel, poll, "poll$NOCANCEL")
+
+FUNC (ERR, int, CLOSE_, close, close, "close")
+FUNCD32 (ERR, int, CLOSE_, close_unix2003, close, "close$UNIX2003")
+FUNCD32 (ERR, int, CLOSE_, close_nocancel_unix2003, close, "close$NOCANCEL$UNIX2003")
+FUNCD64 (ERR, int, CLOSE_, close_nocancel, close, "close$NOCANCEL")
+
+FUNC (ERR, int, GETPEERNAME_, getpeername, getpeername, "getpeername")
+FUNCD32 (ERR, int, GETPEERNAME_, getpeername_unix2003, getpeername, "getpeername$UNIX2003")
diff --git a/src.old/parser.c b/src.old/parser.c
new file mode 100644
index 0000000..8f24be6
--- /dev/null
+++ b/src.old/parser.c
@@ -0,0 +1,872 @@
+/***************************************************************************
+ * *
+ * Copyright (C) 2000-2008 Shaun Clowes <delius@xxxxxxxxxxx> *
+ * Copyright (C) 2008-2011 Robert Hogan <robert@xxxxxxxxxxxxxxx> *
+ * *
+ * 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. *
+ ***************************************************************************/
+/*
+
+ parser.c - Parsing routines for torsocks.conf
+
+*/
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <config.h>
+
+#include "common.h"
+#include "parser.h"
+
+/* Global configuration variables */
+#define MAXLINE BUFSIZ /* Max length of conf line */
+static struct serverent *currentcontext = NULL;
+
+static int handle_line(struct parsedfile *, char *, int);
+static int check_server(struct serverent *);
+static int tokenize(char *, int, char *[]);
+static int handle_path(struct parsedfile *, int, int, char *[]);
+static int handle_endpath(struct parsedfile *, int, int);
+static int handle_reaches(int, char *);
+static int handle_server(struct parsedfile *, int, char *);
+static int handle_type(struct parsedfile *config, int, char *);
+static int handle_port(struct parsedfile *config, int, char *);
+static int handle_local(struct parsedfile *, int, const char *);
+static int handle_tordns_enabled(struct parsedfile *, int, char *);
+static int handle_tordns_deadpool_range(struct parsedfile *, int, const char *);
+static int handle_tordns_cache_size(struct parsedfile *, char *);
+static int handle_defuser(struct parsedfile *, int, char *);
+static int handle_defpass(struct parsedfile *, int, char *);
+static int make_netent(char *value, struct netent **ent);
+
+int read_config (char *filename, struct parsedfile *config) {
+ FILE *conf;
+ char line[MAXLINE];
+ int rc = 0;
+ int lineno = 1;
+ struct serverent *server;
+
+ /* Clear out the structure */
+ memset(config, 0x0, sizeof(*config));
+
+ /* Initialization */
+ currentcontext = &(config->defaultserver);
+
+ /* Tordns defaults */
+ config->tordns_cache_size = 256;
+ config->tordns_enabled = 1;
+
+
+ /* If a filename wasn't provided, use the default */
+ if (filename == NULL) {
+ strncpy(line, CONF_FILE, sizeof(line) - 1);
+ /* Insure null termination */
+ line[sizeof(line) - 1] = (char) 0;
+ filename = line;
+ show_msg(MSGDEBUG, "Configuration file not provided by TORSOCKS_CONF_FILE "
+ "environment variable, attempting to use defaults in %s.\n", filename);
+ }
+
+ /* If there is no configuration file use reasonable defaults for Tor */
+ if ((conf = fopen(filename, "r")) == NULL) {
+ show_msg(MSGERR, "Could not open socks configuration file "
+ "(%s) errno (%d), assuming sensible defaults for Tor.\n", filename, errno);
+ memset(&(config->defaultserver), 0x0, sizeof(config->defaultserver));
+ check_server(&(config->defaultserver));
+ handle_local(config, 0, "127.0.0.0/255.0.0.0");
+ handle_local(config, 0, "10.0.0.0/255.0.0.0");
+ handle_local(config, 0, "192.168.0.0/255.255.0.0");
+ handle_local(config, 0, "172.16.0.0/255.240.0.0");
+ handle_local(config, 0, "169.254.0.0/255.255.0.0");
+ rc = 1; /* Severe errors reading configuration */
+ } else {
+ memset(&(config->defaultserver), 0x0, sizeof(config->defaultserver));
+
+ while (NULL != fgets(line, MAXLINE, conf)) {
+ /* This line _SHOULD_ end in \n so we */
+ /* just chop off the \n and hand it on */
+ if (strlen(line) > 0)
+ line[strlen(line) - 1] = '\0';
+ handle_line(config, line, lineno);
+ lineno++;
+ }
+ fclose(conf);
+
+ /* Always add the 127.0.0.1/255.0.0.0 subnet to local */
+ handle_local(config, 0, "127.0.0.0/255.0.0.0");
+ /* We always consider this local, because many users' dsl
+ routers act as their DNS. */
+ handle_local(config, 0, "10.0.0.0/255.0.0.0");
+ handle_local(config, 0, "192.168.0.0/255.255.0.0");
+ handle_local(config, 0, "172.16.0.0/255.240.0.0");
+ handle_local(config, 0, "169.254.0.0/255.255.0.0");
+ handle_local(config, 0, "192.168.0.0/255.255.0.0");
+
+ /* Check default server */
+ check_server(&(config->defaultserver));
+ server = (config->paths);
+ while (server != NULL) {
+ check_server(server);
+ server = server->next;
+ }
+ }
+
+ /* Initialize tordns deadpool_range if not supplied */
+ if(config->tordns_deadpool_range == NULL) {
+ handle_tordns_deadpool_range(config, 0, "127.0.69.0/255.255.255.0");
+ }
+
+ return(rc);
+}
+
+/* Check server entries (and establish defaults) */
+static int check_server(struct serverent *server) {
+
+ /* Default to the default Tor Socks port */
+ if (server->port == 0) {
+ server->port = 9050;
+ }
+
+ /* Default to a presumably local installation of Tor */
+ if (server->address == NULL) {
+ server->address = strdup("127.0.0.1");
+ }
+
+ /* Default to SOCKS V4 */
+ if (server->type == 0) {
+ server->type = 4;
+ }
+
+ return(0);
+}
+
+
+
+static int handle_line(struct parsedfile *config, char *line, int lineno) {
+ char *words[10];
+ static char savedline[MAXLINE];
+ int nowords = 0, i;
+
+ /* Save the input string */
+ strncpy(savedline, line, MAXLINE - 1);
+ savedline[MAXLINE - 1] = (char) 0;
+ /* Tokenize the input string */
+ nowords = tokenize(line, 10, words);
+
+ /* Set the spare slots to an empty string to simplify */
+ /* processing */
+ for (i = nowords; i < 10; i++)
+ words[i] = NULL;
+
+ if (nowords > 0) {
+ /* Now this can either be a "path" block starter or */
+ /* ender, otherwise it has to be a pair (<name> = */
+ /* <value>) */
+ if (!strcmp(words[0], "path")) {
+ handle_path(config, lineno, nowords, words);
+ } else if (!strcmp(words[0], "}")) {
+ handle_endpath(config, lineno, nowords);
+ } else {
+ /* Has to be a pair */
+ if ((nowords != 3) || (strcmp(words[1], "="))) {
+ show_msg(MSGERR, "Malformed configuration pair "
+ "on line %d in configuration "
+ "file, \"%s\"\n", lineno, savedline);
+ } else if (!strcmp(words[0], "reaches")) {
+ handle_reaches(lineno, words[2]);
+ } else if (!strcmp(words[0], "server")) {
+ handle_server(config, lineno, words[2]);
+ } else if (!strcmp(words[0], "server_port")) {
+ handle_port(config, lineno, words[2]);
+ } else if (!strcmp(words[0], "server_type")) {
+ handle_type(config, lineno, words[2]);
+ } else if (!strcmp(words[0], "default_user")) {
+ handle_defuser(config, lineno, words[2]);
+ } else if (!strcmp(words[0], "default_pass")) {
+ handle_defpass(config, lineno, words[2]);
+ } else if (!strcmp(words[0], "local")) {
+ handle_local(config, lineno, words[2]);
+ } else if (!strcmp(words[0], "tordns_enable")) {
+ handle_tordns_enabled(config, lineno, words[2]);
+ } else if (!strcmp(words[0], "tordns_deadpool_range")) {
+ handle_tordns_deadpool_range(config, lineno, words[2]);
+ } else if (!strcmp(words[0], "tordns_cache_size")) {
+ handle_tordns_cache_size(config, words[2]);
+ } else {
+ show_msg(MSGERR, "Invalid pair type (%s) specified "
+ "on line %d in configuration file, "
+ "\"%s\"\n", words[0], lineno,
+ savedline);
+ }
+ }
+ }
+
+ return(0);
+}
+
+/* This routines breaks up input lines into tokens */
+/* and places these tokens into the array specified */
+/* by tokens */
+static int tokenize(char *line, int arrsize, char *tokens[]) {
+ int tokenno = -1;
+ int finished = 0;
+
+ /* Whitespace is ignored before and after tokens */
+ while ((tokenno < (arrsize - 1)) &&
+ (line = line + strspn(line, " \t")) &&
+ (*line != (char) 0) &&
+ (!finished)) {
+ tokenno++;
+ tokens[tokenno] = line;
+ line = line + strcspn(line, " \t");
+ *line = (char) 0;
+ line++;
+
+ /* We ignore everything after a # */
+ if (*tokens[tokenno] == '#') {
+ finished = 1;
+ tokenno--;
+ }
+ }
+
+ return(tokenno + 1);
+}
+
+static int handle_path(struct parsedfile *config, int lineno, int nowords, char *words[]) {
+ struct serverent *newserver;
+
+ if ((nowords != 2) || (strcmp(words[1], "{"))) {
+ show_msg(MSGERR, "Badly formed path open statement on line %d "
+ "in configuration file (should look like "
+ "\"path {\")\n", lineno);
+ } else if (currentcontext != &(config->defaultserver)) {
+ /* You cannot nest path statements so check that */
+ /* the current context is defaultserver */
+ show_msg(MSGERR, "Path statements cannot be nested on line %d "
+ "in configuration file\n", lineno);
+ } else {
+ /* Open up a new serverent, put it on the list */
+ /* then set the current context */
+ if ((newserver = malloc(sizeof(*newserver))) == NULL)
+ exit(-1);
+
+ /* Initialize the structure */
+ show_msg(MSGDEBUG, "New server structure from line %d in configuration file going "
+ "to 0x%08x\n", lineno, newserver);
+ memset(newserver, 0x0, sizeof(*newserver));
+ newserver->next = config->paths;
+ newserver->lineno = lineno;
+ config->paths = newserver;
+ currentcontext = newserver;
+ }
+
+ return(0);
+}
+
+static int handle_endpath(struct parsedfile *config, int lineno, int nowords) {
+
+ if (nowords != 1) {
+ show_msg(MSGERR, "Badly formed path close statement on line "
+ "%d in configuration file (should look like "
+ "\"}\")\n", lineno);
+ } else {
+ currentcontext = &(config->defaultserver);
+ }
+
+ /* We could perform some checking on the validty of data in */
+ /* the completed path here, but thats what verifyconf is */
+ /* designed to do, no point in weighing down libtorsocks */
+
+ return(0);
+}
+
+static int handle_reaches(int lineno, char *value) {
+ int rc;
+ struct netent *ent;
+
+ rc = make_netent(value, &ent);
+ switch(rc) {
+ case 1:
+ show_msg(MSGERR, "Local network specification (%s) is not validly "
+ "constructed in reach statement on line "
+ "%d in configuration "
+ "file\n", value, lineno);
+ return(0);
+ break;
+ case 2:
+ show_msg(MSGERR, "IP in reach statement "
+ "network specification (%s) is not valid on line "
+ "%d in configuration file\n", value, lineno);
+ return(0);
+ break;
+ case 3:
+ show_msg(MSGERR, "SUBNET in reach statement "
+ "network specification (%s) is not valid on "
+ "line %d in configuration file\n", value,
+ lineno);
+ return(0);
+ break;
+ case 4:
+ show_msg(MSGERR, "IP (%s) & ", inet_ntoa(ent->localip));
+ show_msg(MSGERR, "SUBNET (%s) != IP on line %d in "
+ "configuration file, ignored\n",
+ inet_ntoa(ent->localnet), lineno);
+ return(0);
+ break;
+ case 5:
+ show_msg(MSGERR, "Start port in reach statement "
+ "network specification (%s) is not valid on line "
+ "%d in configuration file\n", value, lineno);
+ return(0);
+ break;
+ case 6:
+ show_msg(MSGERR, "End port in reach statement "
+ "network specification (%s) is not valid on line "
+ "%d in configuration file\n", value, lineno);
+ return(0);
+ break;
+ case 7:
+ show_msg(MSGERR, "End port in reach statement "
+ "network specification (%s) is less than the start "
+ "port on line %d in configuration file\n", value,
+ lineno);
+ return(0);
+ break;
+ }
+
+ /* The entry is valid so add it to linked list */
+ ent -> next = currentcontext -> reachnets;
+ currentcontext -> reachnets = ent;
+
+ return(0);
+}
+
+static int handle_server(struct parsedfile *config, int lineno, char *value) {
+ char *ip;
+
+ ip = strsplit(NULL, &value, " ");
+
+ /* We don't verify this ip/hostname at this stage, */
+ /* its resolved immediately before use in torsocks.c */
+ if (currentcontext->address == NULL)
+ currentcontext->address = strdup(ip);
+ else {
+ if (currentcontext == &(config->defaultserver))
+ show_msg(MSGERR, "Only one default SOCKS server "
+ "may be specified at line %d in "
+ "configuration file\n", lineno);
+ else
+ show_msg(MSGERR, "Only one SOCKS server may be specified "
+ "per path on line %d in configuration "
+ "file. (Path begins on line %d)\n",
+ lineno, currentcontext->lineno);
+ }
+
+ return(0);
+}
+
+static int handle_port(struct parsedfile *config, int lineno, char *value) {
+
+ if (currentcontext->port != 0) {
+ if (currentcontext == &(config->defaultserver))
+ show_msg(MSGERR, "Server port may only be specified "
+ "once for default server, at line %d "
+ "in configuration file\n", lineno);
+ else
+ show_msg(MSGERR, "Server port may only be specified "
+ "once per path on line %d in configuration "
+ "file. (Path begins on line %d)\n",
+ lineno, currentcontext->lineno);
+ } else {
+ errno = 0;
+ currentcontext->port = (unsigned short int)
+ (strtol(value, (char **)NULL, 10));
+ if ((errno != 0) || (currentcontext->port == 0)) {
+ show_msg(MSGERR, "Invalid server port number "
+ "specified in configuration file "
+ "(%s) on line %d\n", value, lineno);
+ currentcontext->port = 0;
+ }
+ }
+
+ return(0);
+}
+
+static int handle_defuser(struct parsedfile *config, int lineno, char *value) {
+
+ if (currentcontext->defuser != NULL) {
+ if (currentcontext == &(config->defaultserver))
+ show_msg(MSGERR, "Default username may only be specified "
+ "once for default server, at line %d "
+ "in configuration file\n", lineno);
+ else
+ show_msg(MSGERR, "Default username may only be specified "
+ "once per path on line %d in configuration "
+ "file. (Path begins on line %d)\n",
+ lineno, currentcontext->lineno);
+ } else {
+ currentcontext->defuser = strdup(value);
+ }
+
+ return(0);
+}
+
+static int handle_defpass(struct parsedfile *config, int lineno, char *value) {
+
+ if (currentcontext->defpass != NULL) {
+ if (currentcontext == &(config->defaultserver))
+ show_msg(MSGERR, "Default password may only be specified "
+ "once for default server, at line %d "
+ "in configuration file\n", lineno);
+ else
+ show_msg(MSGERR, "Default password may only be specified "
+ "once per path on line %d in configuration "
+ "file. (Path begins on line %d)\n",
+ lineno, currentcontext->lineno);
+ } else {
+ currentcontext->defpass = strdup(value);
+ }
+
+ return(0);
+}
+
+static int handle_type(struct parsedfile *config, int lineno, char *value) {
+
+ if (currentcontext->type != 0) {
+ if (currentcontext == &(config->defaultserver))
+ show_msg(MSGERR, "Server type may only be specified "
+ "once for default server, at line %d "
+ "in configuration file\n", lineno);
+ else
+ show_msg(MSGERR, "Server type may only be specified "
+ "once per path on line %d in configuration "
+ "file. (Path begins on line %d)\n",
+ lineno, currentcontext->lineno);
+ } else {
+ errno = 0;
+ currentcontext->type = (int) strtol(value, (char **)NULL, 10);
+ if ((errno != 0) || (currentcontext->type == 0) ||
+ ((currentcontext->type != 4) && (currentcontext->type != 5))) {
+ show_msg(MSGERR, "Invalid server type (%s) "
+ "specified in configuration file "
+ "on line %d, only 4 or 5 may be "
+ "specified\n", value, lineno);
+ currentcontext->type = 0;
+ }
+ }
+
+ return(0);
+}
+
+static int handle_flag(char *value)
+{
+ if(!strcasecmp(value, "true") || !strcasecmp(value, "yes")
+ || !strcmp(value, "1")) {
+ return 1;
+ } else if (!strcasecmp(value, "false") || !strcasecmp(value, "no")
+ || !strcmp(value, "0")) {
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+static int handle_tordns_enabled(struct parsedfile *config, int lineno,
+ char *value)
+{
+ int val = handle_flag(value);
+ if(val == -1) {
+ show_msg(MSGERR, "Invalid value %s supplied for tordns_enabled at "
+ "line %d in config file, IGNORED\n", value, lineno);
+ } else {
+ config->tordns_enabled = val;
+ }
+ return 0;
+}
+
+static int handle_tordns_cache_size(struct parsedfile *config,
+ char *value)
+{
+ char *endptr;
+ long size = strtol(value, &endptr, 10);
+ if(*endptr != '\0') {
+ show_msg(MSGERR, "Error parsing integer value for "
+ "tordns_cache_size (%s), using default %d\n",
+ value, config->tordns_cache_size);
+ } else if(size < 128) {
+ show_msg(MSGERR, "The value supplied for tordns_cache_size (%d) "
+ "is too small (<128), using default %d\n", size,
+ config->tordns_cache_size);
+ } else if(size > 4096) {
+ show_msg(MSGERR, "The value supplied for tordns_cache_range (%d) "
+ "is too large (>4096), using default %d\n", size,
+ config->tordns_cache_size);
+ } else {
+ config->tordns_cache_size = size;
+ }
+ return 0;
+}
+
+static int handle_tordns_deadpool_range(struct parsedfile *config, int lineno,
+ const char *value)
+{
+ int rc;
+ struct netent *ent;
+
+ if (config->tordns_deadpool_range != NULL) {
+ show_msg(MSGERR, "Only one 'deadpool' entry permitted, found a "
+ "second at line %d in configuration file.\n");
+ return(0);
+ }
+
+ if (currentcontext != &(config->defaultserver)) {
+ show_msg(MSGERR, "Deadpool cannot be specified in path "
+ "block at line %d in configuration file. "
+ "(Path block started at line %d)\n",
+ lineno, currentcontext->lineno);
+ return(0);
+ }
+
+ rc = make_netent((char *)value, &ent);
+ /* This is copied from handle_local and should probably be folded into
+ a generic whinge() function or something */
+ switch(rc) {
+ case 1:
+ show_msg(MSGERR, "The deadpool specification (%s) is not validly "
+ "constructed on line %d in configuration "
+ "file\n", value, lineno);
+ return(0);
+ break;
+ case 2:
+ show_msg(MSGERR, "IP for deadpool "
+ "network specification (%s) is not valid on line "
+ "%d in configuration file\n", value, lineno);
+ return(0);
+ break;
+ case 3:
+ show_msg(MSGERR, "SUBNET for "
+ "deadpool network specification (%s) is not valid on "
+ "line %d in configuration file\n", value,
+ lineno);
+ return(0);
+ break;
+ case 4:
+ show_msg(MSGERR, "IP (%s) & ", inet_ntoa(ent->localip));
+ show_msg(MSGERR, "SUBNET (%s) != IP on line %d in "
+ "configuration file, ignored\n",
+ inet_ntoa(ent->localnet), lineno);
+ return(0);
+ case 5:
+ case 6:
+ case 7:
+ show_msg(MSGERR, "Port specification is invalid and "
+ "not allowed in deadpool specification "
+ "(%s) on line %d in configuration file\n",
+ value, lineno);
+ return(0);
+ break;
+ }
+ if (ent->startport || ent->endport) {
+ show_msg(MSGERR, "Port specification is "
+ "not allowed in deadpool specification "
+ "(%s) on line %d in configuration file\n",
+ value, lineno);
+ return(0);
+ }
+
+ config->tordns_deadpool_range = ent;
+ return 0;
+}
+
+static int handle_local(struct parsedfile *config, int lineno, const char *value) {
+ int rc;
+ struct netent *ent;
+
+ if (currentcontext != &(config->defaultserver)) {
+ show_msg(MSGERR, "Local networks cannot be specified in path "
+ "block at line %d in configuration file. "
+ "(Path block started at line %d)\n",
+ lineno, currentcontext->lineno);
+ return(0);
+ }
+
+ rc = make_netent((char *)value, &ent);
+ switch(rc) {
+ case 1:
+ show_msg(MSGERR, "Local network specification (%s) is not validly "
+ "constructed on line %d in configuration "
+ "file\n", value, lineno);
+ return(0);
+ break;
+ case 2:
+ show_msg(MSGERR, "IP for local "
+ "network specification (%s) is not valid on line "
+ "%d in configuration file\n", value, lineno);
+ return(0);
+ break;
+ case 3:
+ show_msg(MSGERR, "SUBNET for "
+ "local network specification (%s) is not valid on "
+ "line %d in configuration file\n", value,
+ lineno);
+ return(0);
+ break;
+ case 4:
+ show_msg(MSGERR, "IP (%s) & ", inet_ntoa(ent->localip));
+ show_msg(MSGERR, "SUBNET (%s) != IP on line %d in "
+ "configuration file, ignored\n",
+ inet_ntoa(ent->localnet), lineno);
+ return(0);
+ case 5:
+ case 6:
+ case 7:
+ show_msg(MSGERR, "Port specification is invalid and "
+ "not allowed in local network specification "
+ "(%s) on line %d in configuration file\n",
+ value, lineno);
+ return(0);
+ break;
+ }
+
+ if (ent->startport || ent->endport) {
+ show_msg(MSGERR, "Port specification is "
+ "not allowed in local network specification "
+ "(%s) on line %d in configuration file\n",
+ value, lineno);
+ return(0);
+ }
+
+ /* The entry is valid so add it to linked list */
+ ent -> next = config->localnets;
+ (config->localnets) = ent;
+
+ return(0);
+}
+
+/* Construct a netent given a string like */
+/* "198.126.0.1[:portno[-portno]]/255.255.255.0" */
+int make_netent(char *value, struct netent **ent) {
+ char *ip;
+ char *subnet;
+ char *startport = NULL;
+ char *endport = NULL;
+ char *badchar;
+ char separator;
+ static char buf[200];
+ char *split;
+
+ /* Get a copy of the string so we can modify it */
+ strncpy(buf, value, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = (char) 0;
+ split = buf;
+
+ /* Now rip it up */
+ ip = strsplit(&separator, &split, "/:");
+ if (separator == ':') {
+ /* We have a start port */
+ startport = strsplit(&separator, &split, "-/");
+ if (separator == '-')
+ /* We have an end port */
+ endport = strsplit(&separator, &split, "/");
+ }
+ subnet = strsplit(NULL, &split, " \n");
+
+ if ((ip == NULL) || (subnet == NULL)) {
+ /* Network specification not validly constructed */
+ return(1);
+ }
+
+ /* Allocate the new entry */
+ if ((*ent = (struct netent *) malloc(sizeof(struct netent)))
+ == NULL) {
+ /* If we couldn't malloc some storage, leave */
+ exit(1);
+ }
+
+ show_msg(MSGDEBUG, "New network entry for %s going to 0x%08x\n", ip, *ent);
+
+ if (!startport)
+ (*ent)->startport = 0;
+ if (!endport)
+ (*ent)->endport = 0;
+
+#ifdef HAVE_INET_ADDR
+ if (((*ent)->localip.s_addr = inet_addr(ip)) == -1) {
+#elif defined(HAVE_INET_ATON)
+ if (!(inet_aton(ip, &((*ent)->localip)))) {
+#endif
+ /* Badly constructed IP */
+ free(*ent);
+ return(2);
+ }
+#ifdef HAVE_INET_ADDR
+ else if (((*ent)->localnet.s_addr = inet_addr(subnet)) == -1) {
+#elif defined(HAVE_INET_ATON)
+ else if (!(inet_aton(subnet, &((*ent)->localnet)))) {
+#endif
+ /* Badly constructed subnet */
+ free(*ent);
+ return(3);
+ } else if (((*ent)->localip.s_addr &
+ (*ent)->localnet.s_addr) !=
+ (*ent)->localip.s_addr) {
+ /* Subnet and Ip != Ip */
+ free(*ent);
+ return(4);
+ } else if (startport &&
+ (!((*ent)->startport = strtol(startport, &badchar, 10)) ||
+ (*badchar != 0) || ((*ent)->startport > 65535))) {
+ /* Bad start port */
+ free(*ent);
+ return(5);
+ } else if (endport &&
+ (!((*ent)->endport = strtol(endport, &badchar, 10)) ||
+ (*badchar != 0) || ((*ent)->endport > 65535))) {
+ /* Bad end port */
+ free(*ent);
+ return(6);
+ } else if (((*ent)->startport > (*ent)->endport) && !(startport && !endport)) {
+ /* End port is less than start port */
+ free(*ent);
+ return(7);
+ }
+
+ if (startport && !endport)
+ (*ent)->endport = (*ent)->startport;
+
+ return(0);
+}
+
+int is_local(struct parsedfile *config, struct in_addr *testip) {
+ struct netent *ent;
+ char buf[16];
+ inet_ntop(AF_INET, testip, buf, sizeof(buf));
+ show_msg(MSGDEBUG, "checking if address: %s is local"
+ "\n",
+ buf);
+
+ for (ent = (config->localnets); ent != NULL; ent = ent -> next) {
+ inet_ntop(AF_INET, &ent->localnet, buf, sizeof(buf));
+ show_msg(MSGDEBUG, "localnet addr: %s"
+ "\n",
+ buf);
+ inet_ntop(AF_INET, &ent->localip, buf, sizeof(buf));
+ show_msg(MSGDEBUG, "localip addr: %s"
+ "\n",
+ buf);
+ show_msg(MSGDEBUG, "result testip->s_addr & ent->localnet.s_addr : %i"
+ "\n",
+ testip->s_addr & ent->localnet.s_addr);
+ show_msg(MSGDEBUG, "result ent->localip.s_addr & ent->localnet.s_addr : %i"
+ "\n",
+ ent->localip.s_addr & ent->localnet.s_addr);
+ show_msg(MSGDEBUG, "result ent->localip.s_addr : %i"
+ "\n",
+ ent->localip.s_addr);
+ if ((testip->s_addr & ent->localnet.s_addr) ==
+ (ent->localip.s_addr & ent->localnet.s_addr)) {
+ show_msg(MSGDEBUG, "address: %s is local"
+ "\n",
+ buf);
+ return(0);
+ }
+ }
+
+ inet_ntop(AF_INET, testip, buf, sizeof(buf));
+ show_msg(MSGDEBUG, "address: %s is not local"
+ "\n",
+ buf);
+ return(1);
+}
+
+/* Find the appropriate server to reach an ip */
+int pick_server(struct parsedfile *config, struct serverent **ent,
+ struct in_addr *ip, unsigned int port) {
+ struct netent *net;
+ char ipbuf[64];
+
+ show_msg(MSGDEBUG, "Picking appropriate server for %s\n", inet_ntoa(*ip));
+ *ent = (config->paths);
+ while (*ent != NULL) {
+ /* Go through all the servers looking for one */
+ /* with a path to this network */
+ show_msg(MSGDEBUG, "Checking SOCKS server %s\n",
+ ((*ent)->address ? (*ent)->address : "(No Address)"));
+ net = (*ent)->reachnets;
+ while (net != NULL) {
+ strcpy(ipbuf, inet_ntoa(net->localip));
+ show_msg(MSGDEBUG, "Server can reach %s/%s\n",
+ ipbuf, inet_ntoa(net->localnet));
+ if (((ip->s_addr & net->localnet.s_addr) ==
+ (net->localip.s_addr & net->localnet.s_addr)) &&
+ (!net->startport ||
+ ((net->startport <= port) && (net->endport >= port))))
+ {
+ show_msg(MSGDEBUG, "This server can reach target\n");
+ /* Found the net, return */
+ return(0);
+ }
+ net = net->next;
+ }
+ (*ent) = (*ent)->next;
+ }
+
+ *ent = &(config->defaultserver);
+
+ return(0);
+}
+
+/* This function is very much like strsep, it looks in a string for */
+/* a character from a list of characters, when it finds one it */
+/* replaces it with a \0 and returns the start of the string */
+/* (basically spitting out tokens with arbitrary separators). If no */
+/* match is found the remainder of the string is returned and */
+/* the start pointer is set to be NULL. The difference between */
+/* standard strsep and this function is that this one will */
+/* set *separator to the character separator found if it isn't null */
+char *strsplit(char *separator, char **text, const char *search) {
+ unsigned int len;
+ char *ret;
+
+ ret = *text;
+
+ if (*text == NULL) {
+ if (separator)
+ *separator = '\0';
+ return(NULL);
+ } else {
+ len = strcspn(*text, search);
+ if (len == strlen(*text)) {
+ if (separator)
+ *separator = '\0';
+ *text = NULL;
+ } else {
+ *text = *text + len;
+ if (separator)
+ *separator = **text;
+ **text = '\0';
+ *text = *text + 1;
+ }
+ }
+
+ return(ret);
+}
diff --git a/src.old/parser.h b/src.old/parser.h
new file mode 100644
index 0000000..91e6d04
--- /dev/null
+++ b/src.old/parser.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+ * *
+ * Copyright (C) 2000-2008 Shaun Clowes <delius@xxxxxxxxxxx> *
+ * Copyright (C) 2008-2011 Robert Hogan <robert@xxxxxxxxxxxxxxx> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+/* parser.h - Structures, functions and global variables for the
+ torsocks parsing routines */
+
+#ifndef _PARSER_H
+
+#define _PARSER_H 1
+
+/* Structure definitions */
+
+/* Structure representing one server specified in the config */
+struct serverent {
+ int lineno; /* Line number in conf file this path started on */
+ char *address; /* Address/hostname of server */
+ int port; /* Port number of server */
+ int type; /* Type of server (4/5) */
+ char *defuser; /* Default username for this socks server */
+ char *defpass; /* Default password for this socks server */
+ struct netent *reachnets; /* Linked list of nets from this server */
+ struct serverent *next; /* Pointer to next server entry */
+};
+
+/* Structure representing a network */
+struct netent {
+ struct in_addr localip; /* Base IP of the network */
+ struct in_addr localnet; /* Mask for the network */
+ unsigned long startport; /* Range of ports for the */
+ unsigned long endport; /* network */
+ struct netent *next; /* Pointer to next network entry */
+};
+
+/* Structure representing a complete parsed file */
+struct parsedfile {
+ struct netent *localnets;
+ struct serverent defaultserver;
+ struct serverent *paths;
+ int tordns_enabled;
+ int tordns_failopen;
+ unsigned int tordns_cache_size;
+ struct netent *tordns_deadpool_range;
+};
+
+/* Functions provided by parser module */
+int read_config(char *, struct parsedfile *);
+int is_local(struct parsedfile *, struct in_addr *);
+int pick_server(struct parsedfile *, struct serverent **, struct in_addr *, unsigned int port);
+char *strsplit(char *separator, char **text, const char *search);
+
+#endif
diff --git a/src.old/socks.c b/src.old/socks.c
new file mode 100644
index 0000000..8497728
--- /dev/null
+++ b/src.old/socks.c
@@ -0,0 +1,633 @@
+/***************************************************************************
+ * *
+ * Copyright (C) 2000-2008 Shaun Clowes <delius@xxxxxxxxxxx> *
+ * Copyright (C) 2008-2011 Robert Hogan <robert@xxxxxxxxxxxxxxx> *
+ * *
+ * 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 <pthread.h>
+#include <stdarg.h>
+#if !defined(__APPLE__) && !defined(__darwin__)
+#include <sys/socket.h>
+#endif
+#include <resolv.h>
+
+#include "common.h"
+#include "dead_pool.h"
+#include "parser.h"
+#include "socks.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);
+
+
+dead_pool *pool = NULL;
+struct connreq *requests = NULL;
+
+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.old/socks.h b/src.old/socks.h
new file mode 100644
index 0000000..6dd497f
--- /dev/null
+++ b/src.old/socks.h
@@ -0,0 +1,116 @@
+/***************************************************************************
+ * *
+ * Copyright (C) 2000-2008 Shaun Clowes <delius@xxxxxxxxxxx> *
+ * Copyright (C) 2008-2011 Robert Hogan <robert@xxxxxxxxxxxxxxx> *
+ * *
+ * 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 */
+extern dead_pool *pool;
+extern struct connreq *requests;
+
+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.old/torsocks.c b/src.old/torsocks.c
new file mode 100644
index 0000000..597c107
--- /dev/null
+++ b/src.old/torsocks.c
@@ -0,0 +1,1108 @@
+/***************************************************************************
+ * *
+ * *
+ * Copyright (C) 2000-2008 Shaun Clowes <delius@xxxxxxxxxxx> *
+ * Copyright (C) 2008-2011 Robert Hogan <robert@xxxxxxxxxxxxxxx> *
+ * *
+ * 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
+
+/* Global configuration variables */
+const char *torsocks_progname = "libtorsocks"; /* Name used in err msgs */
+
+/* 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 <pthread.h>
+#include <stdarg.h>
+#if !defined(__APPLE__) && !defined(__darwin__)
+#include <sys/socket.h>
+#endif
+#include <resolv.h>
+
+#include "common.h"
+#include "dead_pool.h"
+#include "parser.h"
+#include "socks.h"
+
+/* Some function names are macroized on Darwin. Allow those names
+ to expand accordingly. */
+#define EXPAND_GUTS(x) torsocks_##x##_guts
+#define EXPAND_GUTS_NAME(x) EXPAND_GUTS(x)
+
+/* Function prototypes for original functions that we patch */
+#ifdef SUPPORT_RES_API
+int (*realres_init)(void);
+#endif
+#define PATCH_TABLE_EXPANSION(e,r,s,n,b,m) r (*real##n)(s##SIGNATURE);
+#include "expansion_table.h"
+#undef PATCH_TABLE_EXPANSION
+#undef DARWIN_EXPANSION
+
+static struct parsedfile config;
+static int suid = 0;
+static char *conffile = NULL;
+
+/* Exported Function Prototypes */
+void __attribute__ ((constructor)) torsocks_init(void);
+
+/* Function prototypes for our patches */
+#ifdef SUPPORT_RES_API
+int res_init(void);
+#endif
+
+#define PATCH_TABLE_EXPANSION(e,r,s,n,b,m) r n(s##SIGNATURE);
+#define DARWIN_EXPANSION(e,r,s,n,b,m) r n(s##SIGNATURE) __asm("_" m);
+#include "expansion_table.h"
+#undef PATCH_TABLE_EXPANSION
+#undef DARWIN_EXPANSION
+
+/* Private Function Prototypes */
+/* no torsocks_res_init_guts */
+#define PATCH_TABLE_EXPANSION(e,r,s,n,b,m) r torsocks_##b##_guts(s##SIGNATURE, r (*original_##b)(s##SIGNATURE));
+#include "expansion_table.h"
+#undef PATCH_TABLE_EXPANSION
+
+static int get_config();
+static int get_environment();
+static int deadpool_init(void);
+
+static pthread_mutex_t torsocks_init_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void torsocks_init(void)
+{
+ pthread_mutex_lock(&torsocks_init_mutex);
+
+ show_msg(MSGDEBUG, "In torsocks_init \n");
+
+ get_environment();
+ get_config();
+
+#ifdef USE_OLD_DLSYM
+ void *lib;
+#endif
+
+ /* We could do all our initialization here, but to be honest */
+ /* most programs that are run won't use our services, so */
+ /* we do our general initialization on first call */
+
+ /* Determine the logging level */
+ suid = (getuid() != geteuid());
+
+ dlerror();
+#ifndef USE_OLD_DLSYM
+ #ifdef SUPPORT_RES_API
+ torsocks_find_library("res_init", MSGERR, realres_init);
+ #endif
+ #define PATCH_TABLE_EXPANSION(e,r,s,n,b,m) torsocks_find_library(m, MSG##e, real##n);
+ #include "expansion_table.h"
+ #undef PATCH_TABLE_EXPANSION
+#else
+ lib = dlopen(LIBCONNECT, RTLD_LAZY);
+ realconnect = dlsym(lib, "connect");
+ realselect = dlsym(lib, "select");
+ realpoll = dlsym(lib, "poll");
+ realgethostbyname = dlsym(lib, "gethostbyname");
+ realgethostbyaddr = dlsym(lib, "gethostbyaddr");
+ realgetaddrinfo = dlsym(lib, "getaddrinfo");
+ realgetipnodebyname = dlsym(lib, "getipnodebyname");
+ realsendto = dlsym(lib, "sendto");
+ realsendmsg = dlsym(lib, "sendmsg");
+ dlclose(lib);
+ lib = dlopen(LIBC, RTLD_LAZY);
+ realclose = dlsym(lib, "close");
+ dlclose(lib);
+ #ifdef SUPPORT_RES_API
+ lib = dlopen(LIBRESOLV, RTLD_LAZY);
+ realres_init = dlsym(lib, "res_init");
+ realresquery = dlsym(lib, "res_query");
+ realressend = dlsym(lib, "res_send");
+ realresquerydomain = dlsym(lib, "res_querydomain");
+ realressearch = dlsym(lib, "res_search");
+ dlclose(lib);
+ #endif
+#endif
+ /* Unfortunately, we can't do this lazily because otherwise our mmap'd
+ area won't be shared across fork()s. */
+ if (!deadpool_init()) {
+ show_msg(MSGERR, "Fatal error: exiting\n");
+ exit(1);
+ }
+
+ pthread_mutex_unlock(&torsocks_init_mutex);
+
+ show_msg(MSGDEBUG, "Exit torsocks_init \n");
+}
+
+static int get_environment()
+{
+ static int done = 0;
+ int loglevel = MSGERR;
+ char *logfile = NULL;
+ char *env;
+
+ if (done)
+ return(0);
+
+ /* Determine the logging level */
+ if ((env = getenv("TORSOCKS_DEBUG")))
+ loglevel = atoi(env);
+ if (((env = getenv("TORSOCKS_DEBUG_FILE"))) && !suid)
+ logfile = env;
+ set_log_options(loglevel, logfile, (loglevel == MSGTEST) ? 0 : 1);
+
+ done = 1;
+
+ return(0);
+}
+
+static int get_config ()
+{
+ static int done = 0;
+
+ if (done)
+ return(0);
+
+ /* Determine the location of the config file */
+#ifdef ALLOW_ENV_CONFIG
+ if (!suid)
+ conffile = getenv("TORSOCKS_CONF_FILE");
+#endif
+
+ /* Read in the config file */
+ read_config(conffile, &config);
+ if (config.paths)
+ show_msg(MSGDEBUG, "First lineno for first path is %d\n", config.paths->lineno);
+
+ done = 1;
+
+ return(0);
+}
+
+/* Patch trampoline functions */
+/* no torsocks_res_init_guts */
+#define PATCH_TABLE_EXPANSION(e,r,s,n,b,m) \
+ r n(s##SIGNATURE) { \
+ if (!real##n) { \
+ torsocks_find_library(m, MSG##e, real##n);\
+ } \
+ return torsocks_##b##_guts(s##ARGNAMES, real##n); \
+ }
+#include "expansion_table.h"
+#undef PATCH_TABLE_EXPANSION
+
+int torsocks_connect_guts(CONNECT_SIGNATURE, int (*original_connect)(CONNECT_SIGNATURE))
+{
+ struct sockaddr_in *connaddr;
+ struct sockaddr_in peer_address;
+ struct sockaddr_in server_address;
+ int gotvalidserver = 0, rc;
+ socklen_t namelen = sizeof(peer_address);
+ int sock_type = -1;
+ socklen_t sock_type_len = sizeof(sock_type);
+ int res = -1;
+ struct serverent *path;
+ struct connreq *newconn;
+
+ /* If the real connect doesn't exist, we're stuffed */
+ if (original_connect == NULL) {
+ show_msg(MSGERR, "Unresolved symbol: connect\n");
+ return(-1);
+ }
+
+ show_msg(MSGTEST, "Got connection request\n");
+
+ connaddr = (struct sockaddr_in *) __addr;
+
+ /* Get the type of the socket */
+ getsockopt(__fd, SOL_SOCKET, SO_TYPE,
+ (void *) &sock_type, &sock_type_len);
+
+ show_msg(MSGDEBUG, "sin_family: %i\n", connaddr->sin_family);
+
+ show_msg(MSGDEBUG, "sockopt: %i \n", sock_type);
+
+ /* If the address is local refuse it. We do this because it could
+ be a TCP DNS request to a local DNS server.*/
+ if (!(is_local(&config, &(connaddr->sin_addr))) &&
+ !is_dead_address(pool, connaddr->sin_addr.s_addr)) {
+ char buf[16];
+ inet_ntop(AF_INET, &(connaddr->sin_addr), buf, sizeof(buf));
+ show_msg(MSGERR, "connect: Connection is to a local address (%s), may be a "
+ "TCP DNS request to a local DNS server so have to reject to be safe. "
+ "Please report a bug to http://code.google.com/p/torsocks/issues/entry if "
+ "this is preventing a program from working properly with torsocks.\n", buf);
+ return -1;
+ }
+
+ /* If this is an INET6, we'll refuse it. */
+ if ((connaddr->sin_family == AF_INET6)) {
+ show_msg(MSGERR, "connect: Connection is IPv6: rejecting.\n");
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+
+ /* If this isn't an INET socket we can't */
+ /* handle it, just call the real connect now */
+ if ((connaddr->sin_family != AF_INET)) {
+ show_msg(MSGDEBUG, "connect: Connection isn't IPv4, ignoring\n");
+ return(original_connect(__fd, __addr, __len));
+ }
+
+ /* If this a UDP socket */
+ /* then we refuse it, since it is probably a DNS request */
+ if ((sock_type != SOCK_STREAM)) {
+ show_msg(MSGERR, "connect: Connection is a UDP or ICMP stream, may be a "
+ "DNS request or other form of leak: rejecting.\n");
+ return -1;
+ }
+
+ /* If we haven't initialized yet, do it now */
+ get_config();
+
+ /* Are we already handling this connect? */
+ if ((newconn = find_socks_request(__fd, 1))) {
+ if (memcmp(&newconn->connaddr, connaddr, sizeof(*connaddr))) {
+ /* Ok, they're calling connect on a socket that is in our
+ * queue but this connect() isn't to the same destination,
+ * they're obviously not trying to check the status of
+ * they're non blocking connect, they must have close()d
+ * the other socket and created a new one which happens
+ * to have the same fd as a request we haven't had the chance
+ * to delete yet, so we delete it here. */
+ show_msg(MSGDEBUG, "Call to connect received on old "
+ "torsocks request for socket %d but to "
+ "new destination, deleting old request\n",
+ newconn->sockid);
+ kill_socks_request(newconn);
+ } else {
+ /* Ok, this call to connect() is to check the status of
+ * a current non blocking connect(). */
+ if (newconn->state == FAILED) {
+ show_msg(MSGDEBUG, "Call to connect received on failed "
+ "request %d, returning %d\n",
+ newconn->sockid, newconn->err);
+ errno = newconn->err;
+ rc = -1;
+ } else if (newconn->state == DONE) {
+ show_msg(MSGERR, "Call to connect received on completed "
+ "request %d\n",
+ newconn->sockid, newconn->err);
+ rc = 0;
+ } else {
+ show_msg(MSGDEBUG, "Call to connect received on current request %d\n",
+ newconn->sockid);
+ rc = handle_request(newconn);
+ errno = rc;
+ }
+ if ((newconn->state == FAILED) || (newconn->state == DONE))
+ kill_socks_request(newconn);
+ return((rc ? -1 : 0));
+ }
+ }
+
+ /* If the socket is already connected, just call connect */
+ /* and get its standard reply */
+ if (!getpeername(__fd, (struct sockaddr *) &peer_address, &namelen)) {
+ show_msg(MSGDEBUG, "Socket is already connected, defering to "
+ "real connect\n");
+ return(original_connect(__fd, __addr, __len));
+ }
+
+ show_msg(MSGDEBUG, "Got connection request for socket %d to "
+ "%s\n", __fd, inet_ntoa(connaddr->sin_addr));
+
+ /* Ok, so its not local, we need a path to the net */
+ pick_server(&config, &path, &(connaddr->sin_addr), ntohs(connaddr->sin_port));
+
+ show_msg(MSGDEBUG, "Picked server %s for connection\n",
+ (path->address ? path->address : "(Not Provided)"));
+ if (path->address == NULL) {
+ if (path == &(config.defaultserver))
+ show_msg(MSGERR, "Connection needs to be made "
+ "via default server but "
+ "the default server has not "
+ "been specified\n");
+ else
+ show_msg(MSGERR, "Connection needs to be made "
+ "via path specified at line "
+ "%d in configuration file but "
+ "the server has not been "
+ "specified for this path\n",
+ path->lineno);
+ } else if ((res = resolve_ip(path->address, 0, 0)) == -1) {
+ show_msg(MSGERR, "The SOCKS server (%s) listed in the configuration "
+ "file which needs to be used for this connection "
+ "is invalid\n", path->address);
+ } else {
+ /* Construct the addr for the socks server */
+ server_address.sin_family = AF_INET; /* host byte order */
+ server_address.sin_addr.s_addr = res;
+ server_address.sin_port = htons(path->port);
+ bzero(&(server_address.sin_zero), 8);
+
+ /* Complain if this server isn't on a localnet */
+ if (is_local(&config, &server_address.sin_addr)) {
+ show_msg(MSGERR, "SOCKS server %s (%s) is not on a local subnet!\n",
+ path->address, inet_ntoa(server_address.sin_addr));
+ } else
+ gotvalidserver = 1;
+ }
+
+ /* If we haven't found a valid server we return connection refused */
+ if (!gotvalidserver ||
+ !(newconn = new_socks_request(__fd, connaddr, &server_address, path))) {
+ errno = ECONNREFUSED;
+ return(-1);
+ } else {
+ /* Now we call the main function to handle the connect. */
+ rc = handle_request(newconn);
+ /* If the request completed immediately it mustn't have been
+ * a non blocking socket, in this case we don't need to know
+ * about this socket anymore. */
+ if ((newconn->state == FAILED) || (newconn->state == DONE))
+ kill_socks_request(newconn);
+ errno = rc;
+ /* We may get either of these if there are no bytes to read from
+ the non-blocking connection in handle_request(). Since we are
+ wrapping connect() here we can't return EWOULDBLOCK/EAGAIN
+ so override it with something the client will accept.*/
+ if (errno == EWOULDBLOCK || errno == EAGAIN)
+ errno = EINPROGRESS;
+ return((rc ? -1 : 0));
+ }
+}
+
+int torsocks_select_guts(SELECT_SIGNATURE, int (*original_select)(SELECT_SIGNATURE))
+{
+ int nevents = 0;
+ int rc = 0;
+ int setevents = 0;
+ int monitoring = 0;
+ struct connreq *conn, *nextconn;
+ fd_set mywritefds, myreadfds, myexceptfds;
+
+ /* If we're not currently managing any requests we can just
+ * leave here */
+ if (!requests) {
+ show_msg(MSGDEBUG, "No requests waiting, calling real select\n");
+ return(original_select(n, readfds, writefds, exceptfds, timeout));
+ }
+
+ show_msg(MSGTEST, "Intercepted call to select\n");
+ show_msg(MSGDEBUG, "Intercepted call to select with %d fds, "
+ "0x%08x 0x%08x 0x%08x, timeout %08x\n", n,
+ readfds, writefds, exceptfds, timeout);
+
+ for (conn = requests; conn != NULL; conn = conn->next) {
+ if ((conn->state == FAILED) || (conn->state == DONE))
+ continue;
+ conn->selectevents = 0;
+ show_msg(MSGDEBUG, "Checking requests for socks enabled socket %d\n",
+ conn->sockid);
+ conn->selectevents |= (writefds ? (FD_ISSET(conn->sockid, writefds) ? WRITE : 0) : 0);
+ conn->selectevents |= (readfds ? (FD_ISSET(conn->sockid, readfds) ? READ : 0) : 0);
+ conn->selectevents |= (exceptfds ? (FD_ISSET(conn->sockid, exceptfds) ? EXCEPT : 0) : 0);
+ if (conn->selectevents) {
+ show_msg(MSGDEBUG, "Socket %d was set for events\n", conn->sockid);
+ monitoring = 1;
+ }
+ }
+
+ if (!monitoring)
+ return(original_select(n, readfds, writefds, exceptfds, timeout));
+
+ /* This is our select loop. In it we repeatedly call select(). We
+ * pass select the same fdsets as provided by the caller except we
+ * modify the fdsets for the sockets we're managing to get events
+ * we're interested in (while negotiating with the socks server). When
+ * events we're interested in happen we go off and process the result
+ * ourselves, without returning the events to the caller. The loop
+ * ends when an event which isn't one we need to handle occurs or
+ * the select times out */
+ do {
+ /* Copy the clients fd events, we'll change them as we wish */
+ if (readfds)
+ memcpy(&myreadfds, readfds, sizeof(myreadfds));
+ else
+ FD_ZERO(&myreadfds);
+ if (writefds)
+ memcpy(&mywritefds, writefds, sizeof(mywritefds));
+ else
+ FD_ZERO(&mywritefds);
+ if (exceptfds)
+ memcpy(&myexceptfds, exceptfds, sizeof(myexceptfds));
+ else
+ FD_ZERO(&myexceptfds);
+
+ /* Now enable our sockets for the events WE want to hear about */
+ for (conn = requests; conn != NULL; conn = conn->next) {
+ if ((conn->state == FAILED) || (conn->state == DONE) ||
+ (conn->selectevents == 0))
+ continue;
+ /* We always want to know about socket exceptions */
+ FD_SET(conn->sockid, &myexceptfds);
+ /* If we're waiting for a connect or to be able to send
+ * on a socket we want to get write events */
+ if ((conn->state == SENDING) || (conn->state == CONNECTING))
+ FD_SET(conn->sockid,&mywritefds);
+ else
+ FD_CLR(conn->sockid,&mywritefds);
+ /* If we're waiting to receive data we want to get
+ * read events */
+ if (conn->state == RECEIVING)
+ FD_SET(conn->sockid,&myreadfds);
+ else
+ FD_CLR(conn->sockid,&myreadfds);
+ }
+
+ nevents = original_select(n, &myreadfds, &mywritefds, &myexceptfds, timeout);
+ /* If there were no events we must have timed out or had an error */
+ if (nevents <= 0)
+ break;
+
+ /* Loop through all the sockets we're monitoring and see if
+ * any of them have had events */
+ for (conn = requests; conn != NULL; conn = nextconn) {
+ nextconn = conn->next;
+ if ((conn->state == FAILED) || (conn->state == DONE))
+ continue;
+ show_msg(MSGDEBUG, "Checking socket %d for events\n", conn->sockid);
+ /* Clear all the events on the socket (if any), we'll reset
+ * any that are necessary later. */
+ setevents = 0;
+ if (FD_ISSET(conn->sockid, &mywritefds)) {
+ nevents--;
+ setevents |= WRITE;
+ show_msg(MSGDEBUG, "Socket had write event\n");
+ FD_CLR(conn->sockid, &mywritefds);
+ }
+ if (FD_ISSET(conn->sockid, &myreadfds)) {
+ nevents--;
+ setevents |= READ;
+ show_msg(MSGDEBUG, "Socket had write event\n");
+ FD_CLR(conn->sockid, &myreadfds);
+ }
+ if (FD_ISSET(conn->sockid, &myexceptfds)) {
+ nevents--;
+ setevents |= EXCEPT;
+ show_msg(MSGDEBUG, "Socket had except event\n");
+ FD_CLR(conn->sockid, &myexceptfds);
+ }
+
+ if (!setevents) {
+ show_msg(MSGDEBUG, "No events on socket %d\n", conn->sockid);
+ continue;
+ }
+
+ if (setevents & EXCEPT)
+ conn->state = FAILED;
+ else
+ rc = handle_request(conn);
+
+ /* If the connection hasn't failed or completed there is nothing
+ * to report to the client */
+ if ((conn->state != FAILED) &&
+ (conn->state != DONE))
+ continue;
+
+ /* Ok, the connection is completed, for good or for bad. We now
+ * hand back the relevant events to the caller. We don't delete the
+ * connection though since the caller should call connect() to
+ * check the status, we delete it then */
+
+ if (conn->state == FAILED) {
+ /* Damn, the connection failed. Whatever the events the socket
+ * was selected for we flag */
+ if (conn->selectevents & EXCEPT) {
+ FD_SET(conn->sockid, &myexceptfds);
+ nevents++;
+ }
+ if (conn->selectevents & READ) {
+ FD_SET(conn->sockid, &myreadfds);
+ nevents++;
+ }
+ if (conn->selectevents & WRITE) {
+ FD_SET(conn->sockid, &mywritefds);
+ nevents++;
+ }
+ /* We should use setsockopt to set the SO_ERROR errno for this
+ * socket, but this isn't allowed for some silly reason which
+ * leaves us a bit hamstrung.
+ * We don't delete the request so that hopefully we can
+ * return the error on the socket if they call connect() on it */
+ } else {
+ /* The connection is done, if the client selected for
+ * writing we can go ahead and signal that now (since the socket must
+ * be ready for writing), otherwise we'll just let the select loop
+ * come around again (since we can't flag it for read, we don't know
+ * if there is any data to be read and can't be bothered checking) */
+ if (conn->selectevents & WRITE) {
+ FD_SET(conn->sockid, &mywritefds);
+ nevents++;
+ }
+ }
+ }
+ } while (nevents == 0);
+
+ show_msg(MSGDEBUG, "Finished intercepting select(), %d events\n", nevents);
+
+ /* Now copy our event blocks back to the client blocks */
+ if (readfds)
+ memcpy(readfds, &myreadfds, sizeof(myreadfds));
+ if (writefds)
+ memcpy(writefds, &mywritefds, sizeof(mywritefds));
+ if (exceptfds)
+ memcpy(exceptfds, &myexceptfds, sizeof(myexceptfds));
+
+ return(nevents);
+}
+
+int torsocks_poll_guts(POLL_SIGNATURE, int (*original_poll)(POLL_SIGNATURE))
+{
+ int nevents = 0;
+ int rc = 0;
+ unsigned int i;
+ int setevents = 0;
+ int monitoring = 0;
+ struct connreq *conn, *nextconn;
+
+ /* If we're not currently managing any requests we can just
+ * leave here */
+ if (!requests)
+ return(original_poll(ufds, nfds, timeout));
+
+ show_msg(MSGTEST, "Intercepted call to poll\n");
+ show_msg(MSGDEBUG, "Intercepted call to poll with %d fds, "
+ "0x%08x timeout %d\n", nfds, ufds, timeout);
+
+ for (conn = requests; conn != NULL; conn = conn->next)
+ conn->selectevents = 0;
+
+ /* Record what events on our sockets the caller was interested
+ * in */
+ for (i = 0; i < nfds; i++) {
+ if (!(conn = find_socks_request(ufds[i].fd, 0)))
+ continue;
+ show_msg(MSGDEBUG, "Have event checks for socks enabled socket %d\n",
+ conn->sockid);
+ conn->selectevents = ufds[i].events;
+ monitoring = 1;
+ }
+
+ if (!monitoring)
+ return(original_poll(ufds, nfds, timeout));
+
+ /* This is our poll loop. In it we repeatedly call poll(). We
+ * pass select the same event list as provided by the caller except we
+ * modify the events for the sockets we're managing to get events
+ * we're interested in (while negotiating with the socks server). When
+ * events we're interested in happen we go off and process the result
+ * ourselves, without returning the events to the caller. The loop
+ * ends when an event which isn't one we need to handle occurs or
+ * the poll times out */
+ do {
+ /* Enable our sockets for the events WE want to hear about */
+ for (i = 0; i < nfds; i++) {
+ if (!(conn = find_socks_request(ufds[i].fd, 0)))
+ continue;
+
+ /* We always want to know about socket exceptions but they're
+ * always returned (i.e they don't need to be in the list of
+ * wanted events to be returned by the kernel */
+ ufds[i].events = 0;
+
+ /* If we're waiting for a connect or to be able to send
+ * on a socket we want to get write events */
+ if ((conn->state == SENDING) || (conn->state == CONNECTING))
+ ufds[i].events |= POLLOUT;
+ /* If we're waiting to receive data we want to get
+ * read events */
+ if (conn->state == RECEIVING)
+ ufds[i].events |= POLLIN;
+ }
+
+ nevents = original_poll(ufds, nfds, timeout);
+ /* If there were no events we must have timed out or had an error */
+ if (nevents <= 0)
+ break;
+
+ /* Loop through all the sockets we're monitoring and see if
+ * any of them have had events */
+ for (conn = requests; conn != NULL; conn = nextconn) {
+ nextconn = conn->next;
+ if ((conn->state == FAILED) || (conn->state == DONE))
+ continue;
+
+ /* Find the socket in the poll list */
+ for (i = 0; ((i < nfds) && (ufds[i].fd != conn->sockid)); i++)
+ /* Empty Loop */;
+ if (i == nfds)
+ continue;
+
+ show_msg(MSGDEBUG, "Checking socket %d for events\n", conn->sockid);
+
+ if (!ufds[i].revents) {
+ show_msg(MSGDEBUG, "No events on socket\n");
+ continue;
+ }
+
+ /* Clear any read or write events on the socket, we'll reset
+ * any that are necessary later. */
+ setevents = ufds[i].revents;
+ if (setevents & POLLIN) {
+ show_msg(MSGDEBUG, "Socket had read event\n");
+ ufds[i].revents &= ~POLLIN;
+ nevents--;
+ }
+ if (setevents & POLLOUT) {
+ show_msg(MSGDEBUG, "Socket had write event\n");
+ ufds[i].revents &= ~POLLOUT;
+ nevents--;
+ }
+ if (setevents & (POLLERR | POLLNVAL | POLLHUP))
+ show_msg(MSGDEBUG, "Socket had error event\n");
+
+ /* Now handle this event */
+ if (setevents & (POLLERR | POLLNVAL | POLLHUP)) {
+ conn->state = FAILED;
+ } else {
+ rc = handle_request(conn);
+ }
+ /* If the connection hasn't failed or completed there is nothing
+ * to report to the client */
+ if ((conn->state != FAILED) &&
+ (conn->state != DONE))
+ continue;
+
+ /* Ok, the connection is completed, for good or for bad. We now
+ * hand back the relevant events to the caller. We don't delete the
+ * connection though since the caller should call connect() to
+ * check the status, we delete it then */
+
+ if (conn->state == FAILED) {
+ /* Damn, the connection failed. Just copy back the error events
+ * from the poll call, error events are always valid even if not
+ * requested by the client */
+ /* We should use setsockopt to set the SO_ERROR errno for this
+ * socket, but this isn't allowed for some silly reason which
+ * leaves us a bit hamstrung.
+ * We don't delete the request so that hopefully we can
+ * return the error on the socket if they call connect() on it */
+ } else {
+ /* The connection is done, if the client polled for
+ * writing we can go ahead and signal that now (since the socket must
+ * be ready for writing), otherwise we'll just let the select loop
+ * come around again (since we can't flag it for read, we don't know
+ * if there is any data to be read and can't be bothered checking) */
+ if (conn->selectevents & POLLOUT) {
+ setevents |= POLLOUT;
+ nevents++;
+ }
+ }
+ }
+ } while (nevents == 0);
+
+ show_msg(MSGDEBUG, "Finished intercepting poll(), %d events\n", nevents);
+
+ /* Now restore the events polled in each of the blocks */
+ for (i = 0; i < nfds; i++) {
+ if (!(conn = find_socks_request(ufds[i].fd, 1)))
+ continue;
+ ufds[i].events = conn->selectevents;
+ }
+
+ return(nevents);
+}
+
+int torsocks_close_guts(CLOSE_SIGNATURE, int (*original_close)(CLOSE_SIGNATURE))
+{
+ int rc;
+ struct connreq *conn;
+
+ /* If we're not currently managing any requests we can just
+ * leave here */
+ if (!requests) {
+ show_msg(MSGDEBUG, "No requests waiting, calling real close\n");
+ return(original_close(fd));
+ }
+
+ if (original_close == NULL) {
+ show_msg(MSGERR, "Unresolved symbol: close\n");
+ return(-1);
+ }
+
+ show_msg(MSGTEST, "Got call to close()\n");
+ show_msg(MSGDEBUG, "Call to close(%d)\n", fd);
+
+ rc = original_close(fd);
+
+ /* If we have this fd in our request handling list we
+ * remove it now */
+ if ((conn = find_socks_request(fd, 1))) {
+ show_msg(MSGDEBUG, "Call to close() received on file descriptor "
+ "%d which is a connection request of status %d\n",
+ conn->sockid, conn->state);
+ kill_socks_request(conn);
+ }
+
+ return(rc);
+}
+
+/* If we are not done setting up the connection yet, return
+ * -1 and ENOTCONN, otherwise call getpeername
+ *
+ * This is necessary since some applications, when using non-blocking connect,
+ * (like ircII) use getpeername() to find out if they are connected already.
+ *
+ * This results in races sometimes, where the client sends data to the socket
+ * before we are done with the socks connection setup. Another solution would
+ * be to intercept send().
+ *
+ * This could be extended to actually set the peername to the peer the
+ * client application has requested, but not for now.
+ *
+ * PP, Sat, 27 Mar 2004 11:30:23 +0100
+ */
+
+int torsocks_getpeername_guts(GETPEERNAME_SIGNATURE,
+ int (*original_getpeername)(GETPEERNAME_SIGNATURE))
+{
+ struct connreq *conn;
+ int rc;
+
+ if (original_getpeername == NULL) {
+ show_msg(MSGERR, "Unresolved symbol: getpeername\n");
+ return(-1);
+ }
+
+ show_msg(MSGTEST, "Intercepted call to getpeername\n");
+ show_msg(MSGDEBUG, "Call to getpeername for fd %d\n", __fd);
+
+
+ rc = original_getpeername(__fd, __name, __namelen);
+ if (rc == -1)
+ return rc;
+
+ /* Are we handling this connect? */
+ if ((conn = find_socks_request(__fd, 1))) {
+ /* While we are at it, we might was well try to do something useful */
+ handle_request(conn);
+
+ if (conn->state != DONE) {
+ errno = ENOTCONN;
+ return(-1);
+ }
+ }
+ return rc;
+}
+
+#ifdef SUPPORT_RES_API
+int res_init(void)
+{
+ int rc;
+
+ if (!realres_init) {
+ torsocks_find_library("res_init", MSGERR, realres_init);
+ }
+
+ show_msg(MSGTEST, "Got res_init request\n");
+
+ if (realres_init == NULL) {
+ show_msg(MSGERR, "Unresolved symbol: res_init\n");
+ return(-1);
+ }
+ /* Call normal res_init */
+ rc = realres_init();
+
+ /* Force using TCP protocol for DNS queries */
+ _res.options |= RES_USEVC;
+ return(rc);
+}
+
+int EXPAND_GUTS_NAME(res_query)(RES_QUERY_SIGNATURE, int (*original_res_query)(RES_QUERY_SIGNATURE))
+{
+ int rc;
+
+ if (!original_res_query) {
+ torsocks_find_library("res_query", MSGERR, original_res_query);
+ }
+
+ show_msg(MSGTEST, "Got res_query request\n");
+
+ if (original_res_query == NULL) {
+ show_msg(MSGERR, "Unresolved symbol: res_query\n");
+ return(-1);
+ }
+
+ /* Ensure we force using TCP for DNS queries by calling res_init
+ above if it has not already been called.*/
+ if (!(_res.options & RES_INIT) || !(_res.options & RES_USEVC))
+ res_init();
+
+ /* Call normal res_query */
+ rc = original_res_query(dname, class, type, answer, anslen);
+
+ return(rc);
+}
+
+int EXPAND_GUTS_NAME(res_querydomain)(RES_QUERYDOMAIN_SIGNATURE, int (*original_res_querydomain)(RES_QUERYDOMAIN_SIGNATURE))
+{
+ int rc;
+
+ if (!original_res_querydomain) {
+ torsocks_find_library("res_querydomain", MSGERR, original_res_querydomain);
+ }
+
+ show_msg(MSGDEBUG, "Got res_querydomain request\n");
+
+ if (original_res_querydomain == NULL) {
+ show_msg(MSGERR, "Unresolved symbol: res_querydomain\n");
+ return(-1);
+ }
+
+ /* Ensure we force using TCP for DNS queries by calling res_init
+ above if it has not already been called.*/
+ if (!(_res.options & RES_INIT) || !(_res.options & RES_USEVC))
+ res_init();
+
+ /* Call normal res_querydomain */
+ rc = original_res_querydomain(name, domain, class, type, answer, anslen);
+
+ return(rc);
+}
+
+int EXPAND_GUTS_NAME(res_search)(RES_SEARCH_SIGNATURE, int (*original_res_search)(RES_SEARCH_SIGNATURE))
+{
+ int rc;
+
+ if (!original_res_search) {
+ torsocks_find_library("res_search", MSGERR, original_res_search);
+ }
+
+ show_msg(MSGTEST, "Got res_search request\n");
+
+ if (original_res_search == NULL) {
+ show_msg(MSGERR, "Unresolved symbol: res_search\n");
+ return(-1);
+ }
+
+ /* Ensure we force using TCP for DNS queries by calling res_init
+ above if it has not already been called.*/
+ if (!(_res.options & RES_INIT) || !(_res.options & RES_USEVC))
+ res_init();
+
+ /* Call normal res_search */
+ rc = original_res_search(dname, class, type, answer, anslen);
+
+ return(rc);
+}
+
+int EXPAND_GUTS_NAME(res_send)(RES_SEND_SIGNATURE, int (*original_res_send)(RES_SEND_SIGNATURE))
+{
+ int rc;
+
+ if (!original_res_send) {
+ torsocks_find_library("res_send", MSGERR, original_res_send);
+ }
+
+ show_msg(MSGTEST, "Got res_send request\n");
+
+ if (original_res_send == NULL) {
+ show_msg(MSGERR, "Unresolved symbol: res_send\n");
+ return(-1);
+ }
+
+ /* Ensure we force using TCP for DNS queries by calling res_init
+ above if it has not already been called.*/
+ if (!(_res.options & RES_INIT) || !(_res.options & RES_USEVC))
+ res_init();
+
+ /* Call normal res_send */
+ rc = original_res_send(msg, msglen, answer, anslen);
+
+ return(rc);
+}
+#endif
+
+static int deadpool_init(void)
+{
+ if (pool)
+ return 1;
+
+ if (!config.tordns_enabled) {
+ show_msg(MSGERR, "Tor DNS is disabled. Check your configuration.\n");
+ return 0;
+ }
+
+ get_environment();
+ get_config();
+ pool = init_pool(config.tordns_cache_size,
+ config.tordns_deadpool_range->localip,
+ config.tordns_deadpool_range->localnet,
+ config.defaultserver.address,
+ config.defaultserver.port);
+
+ if (!pool) {
+ show_msg(MSGERR, "Could not initialize reserved addresses for "
+ ".onion addresses. Torsocks will not work properly.\n");
+ return 0;
+ }
+ return 1;
+}
+
+struct hostent *torsocks_gethostbyname_guts(GETHOSTBYNAME_SIGNATURE, struct hostent *(*original_gethostbyname)(GETHOSTBYNAME_SIGNATURE))
+{
+ if (pool)
+ return our_gethostbyname(pool, name);
+ return original_gethostbyname(name);
+}
+
+struct hostent *torsocks_gethostbyaddr_guts(GETHOSTBYADDR_SIGNATURE, struct hostent *(*original_gethostbyaddr)(GETHOSTBYADDR_SIGNATURE))
+{
+ if (pool)
+ return our_gethostbyaddr(pool, addr, len, type);
+ return original_gethostbyaddr(addr, len, type);
+}
+
+int torsocks_getaddrinfo_guts(GETADDRINFO_SIGNATURE, int (*original_getaddrinfo)(GETADDRINFO_SIGNATURE))
+{
+ if (pool)
+ return our_getaddrinfo(pool, node, service, hints, res);
+ return original_getaddrinfo(node, service, hints, res);
+}
+
+struct hostent *torsocks_getipnodebyname_guts(GETIPNODEBYNAME_SIGNATURE, struct hostent *(*original_getipnodebyname)(GETIPNODEBYNAME_SIGNATURE))
+{
+ if (pool)
+ return our_getipnodebyname(pool, name, af, flags, error_num);
+ return original_getipnodebyname(name, af, flags, error_num);
+}
+
+ssize_t torsocks_sendto_guts(SENDTO_SIGNATURE, ssize_t (*original_sendto)(SENDTO_SIGNATURE))
+{
+ int sock_type = -1;
+ unsigned int sock_type_len = sizeof(sock_type);
+ struct sockaddr_in *connaddr;
+
+ /* If the real sendto doesn't exist, we're stuffed */
+ if (original_sendto == NULL) {
+ show_msg(MSGERR, "Unresolved symbol: sendto\n");
+ return(-1);
+ }
+
+ show_msg(MSGTEST, "Got sendto request\n");
+
+ /* Get the type of the socket */
+ getsockopt(s, SOL_SOCKET, SO_TYPE,
+ (void *) &sock_type, &sock_type_len);
+
+ show_msg(MSGDEBUG, "sockopt: %i\n", sock_type);
+
+ /* If this a UDP socket then we refuse it, since it is probably a DNS
+ request */
+ if ((sock_type != SOCK_STREAM)) {
+ show_msg(MSGERR, "sendto: Connection is a UDP or ICMP stream, may be a "
+ "DNS request or other form of leak: rejecting.\n");
+ return -1;
+ }
+
+ connaddr = (struct sockaddr_in *) to;
+
+ /* If there is no address in 'to', sendto will only work if we
+ already allowed the socket to connect(), so we let it through.
+ Likewise if the socket is not an Internet connection. */
+ if (connaddr && (connaddr->sin_family != AF_INET)) {
+ show_msg(MSGDEBUG, "Connection isn't an Internet socket ignoring\n");
+ }
+
+ return (ssize_t) original_sendto(s, buf, len, flags, to, tolen);
+}
+
+ssize_t torsocks_sendmsg_guts(SENDMSG_SIGNATURE, ssize_t (*original_sendmsg)(SENDMSG_SIGNATURE))
+{
+ int sock_type = -1;
+ unsigned int sock_type_len = sizeof(sock_type);
+ struct sockaddr_in *connaddr;
+
+ /* If the real sendmsg doesn't exist, we're stuffed */
+ if (original_sendmsg == NULL) {
+ show_msg(MSGERR, "Unresolved symbol: sendmsg\n");
+ return(-1);
+ }
+
+ show_msg(MSGTEST, "Got sendmsg request\n");
+
+ /* Get the type of the socket */
+ getsockopt(s, SOL_SOCKET, SO_TYPE,
+ (void *) &sock_type, &sock_type_len);
+
+ show_msg(MSGDEBUG, "sockopt: %i\n", sock_type);
+
+ if ((sock_type != SOCK_STREAM)) {
+ show_msg(MSGERR, "sendmsg: Connection is a UDP or ICMP stream, may be a "
+ "DNS request or other form of leak: rejecting.\n");
+ return -1;
+ }
+
+ connaddr = (struct sockaddr_in *) msg->msg_name;
+
+ /* If there is no address in msg_name, sendmsg will only work if we
+ already allowed the socket to connect(), so we let it through.
+ Likewise if the socket is not an Internet connection. */
+ if (connaddr && (connaddr->sin_family != AF_INET)) {
+ show_msg(MSGDEBUG, "Connection isn't an Internet socket\n");
+ }
+
+ return (ssize_t) original_sendmsg(s, msg, flags);
+}
+
diff --git a/src.old/torsocks.in b/src.old/torsocks.in
new file mode 100755
index 0000000..4eaed8f
--- /dev/null
+++ b/src.old/torsocks.in
@@ -0,0 +1,167 @@
+#!/bin/sh
+# ***************************************************************************
+# * *
+# * *
+# * Copyright (C) 2008 by Robert Hogan *
+# * robert@xxxxxxxxxxxxxxx *
+# * Copyright (C) 2012 by Jacob Appelbaum <jacob@xxxxxxxxxxxxxx> *
+# * *
+# * 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. *
+# ***************************************************************************
+# * *
+# * This is a modified version of a source file from the Tor project. *
+# * Original copyright information follows: *
+# ***************************************************************************
+# Wrapper script for use of the torsocks(8) transparent socksification library
+#
+# There are three forms of usage for this script:
+#
+# @prefix@/bin/torsocks program [program arguments...]
+#
+# This form sets the users @LDPRELOAD@ environment variable so that torsocks(8)
+# will be loaded to socksify the application then executes the specified
+# program (with the provided arguments). The following simple example might
+# be used to telnet to www.foo.org via a torsocks.conf(5) configured socks server:
+#
+# @prefix@/bin/torsocks telnet www.foo.org
+#
+# The second form allows for torsocks(8) to be switched on and off for a
+# session (that is, it adds and removes torsocks from the @LDPRELOAD@ environment
+# variable). This form must be _sourced_ into the user's existing session
+# (and will only work with bourne shell users):
+#
+# . @prefix@/bin/torsocks on
+# telnet www.foo.org
+# . @prefix@/bin/torsocks off
+#
+# Or
+#
+# source @prefix@/bin/torsocks on
+# telnet www.foo.org
+# source @prefix@/bin/torsocks off
+#
+# The third form creates a new shell with @LDPRELOAD@ set and is achieved
+# simply by running the script with no arguments
+#
+# @prefix@/bin/torsocks
+#
+# When finished the user can simply terminate the shell with 'exit'
+#
+# This script is originally from the debian torsocks package by
+# Tamas Szerb <toma@xxxxxxxxx>
+# Modified by Robert Hogan <robert@xxxxxxxxxxxxxxx> April 16th 2006
+
+not_found () {
+ echo "ERROR: $1 cannot be found in PATH." >&2
+ exit 1
+}
+
+set_id () {
+ echo "ERROR: $1 is set${2}id. torsocks will not work on a set${2}id executable." >&2
+ exit 1
+}
+
+if [ $# = 0 ] ; then
+ echo "$0: insufficient arguments"
+ exit
+fi
+
+LIBDIR="@prefix@/lib/torsocks"
+LIB_NAME="libtorsocks"
+SHLIB_EXT="@SHLIB_EXT@"
+SHLIB="${LIBDIR}/${LIB_NAME}.${SHLIB_EXT}"
+
+# Check for libtorsocks and if set the 64bit variant
+if [ ! -f $SHLIB ]; then
+ LIBDIR="@prefix@/lib64/torsocks"
+ SHLIB="${LIBDIR}/${LIB_NAME}.${SHLIB_EXT}"
+fi
+
+# Ensure libtorsocks exists,
+if [ ! -f $SHLIB ]; then
+ echo "$0: $SHLIB does not exist! Try re-installing torsocks."
+ exit
+fi
+
+case "$1" in
+ on)
+ if [ -z "$@LDPRELOAD@" ]
+ then
+ export @LDPRELOAD@="${SHLIB}"
+ else
+ echo $@LDPRELOAD@ | grep -q "${SHLIB}" || \
+ export @LDPRELOAD@="${SHLIB} $@LDPRELOAD@"
+ fi
+ # FIXME: This env variable is only meaningful on Mac OSX, so it would be better
+ # not to set it at all on other platforms.
+ export DYLD_FORCE_FLAT_NAMESPACE=1
+ ;;
+ off)
+ #replace '/' with '\/' in @prefix@
+ # escprefix=`echo '@prefix@' |sed 's/\\//\\\\\//g'`
+ # export @LDPRELOAD@=`echo -n $@LDPRELOAD@ | sed "s/$escprefix\/lib\/torsocks\/libtorsocks.so \?//"`
+ export @LDPRELOAD@=`echo -n $@LDPRELOAD@ | sed "s#@prefix@/lib/torsocks/libtorsocks\.@SHLIB_EXT@ *##"`
+ if [ -z "$@LDPRELOAD@" ]
+ then
+ unset @LDPRELOAD@
+ # FIXME: This env variable is only meaningful on Mac OSX, so it would be better
+ # not to set it at all on other platforms.
+ unset DYLD_FORCE_FLAT_NAMESPACE=1
+ fi
+ ;;
+ show|sh)
+ echo "@LDPRELOAD@=\"$@LDPRELOAD@\""
+ ;;
+ -h|-?)
+ echo "$0: Please see torsocks(1) or read comment at top of $0"
+ ;;
+ --shell)
+ if [ -z "$@LDPRELOAD@" ]
+ then
+ export @LDPRELOAD@="${SHLIB}"
+ else
+ echo $@LDPRELOAD@ | grep -q "${SHLIB}" || \
+ export @LDPRELOAD@="${SHLIB} $@LDPRELOAD@"
+ fi
+ export DYLD_FORCE_FLAT_NAMESPACE=1
+ echo "torsocks: new torified shell coming right up..."
+ ${SHELL:-/bin/sh}
+ ;;
+ *)
+ if [ -z "$@LDPRELOAD@" ]
+ then
+ export @LDPRELOAD@="${SHLIB}"
+ else
+ echo $@LDPRELOAD@ | grep -q "${SHLIB}" || \
+ export @LDPRELOAD@="${SHLIB} $@LDPRELOAD@"
+ fi
+ export DYLD_FORCE_FLAT_NAMESPACE=1
+
+ if [ $# -gt 0 ]
+ then
+ if ! which "$1" >/dev/null 2>&1; then
+ not_found $1
+ elif [ -u `which "$1"` ]; then
+ set_id $1 u
+ elif [ -g `which "$1"` ]; then
+ set_id $1 g
+ fi
+ exec "$@"
+ fi
+ ;;
+esac
+
+#EOF
diff --git a/src.old/usewithtor.in b/src.old/usewithtor.in
new file mode 100644
index 0000000..e606760
--- /dev/null
+++ b/src.old/usewithtor.in
@@ -0,0 +1,113 @@
+#! /bin/sh
+# ***************************************************************************
+# * *
+# * Copyright (C) 2008-2011 Robert Hogan <robert@xxxxxxxxxxxxxxx> *
+# * *
+# * 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. *
+# ***************************************************************************
+# * *
+# * This is a modified version of a source file from the Tor project. *
+# * Original copyright notice from tsocks source file follows: *
+# ***************************************************************************
+
+# Wrapper script for use of the tsocks(8) transparent socksification library
+# See the tsocks(1) and torify(1) manpages.
+
+# Copyright (c) 2004, 2006 Peter Palfrader
+# Modified by Jacob Appelbaum <jacob@xxxxxxxxxxxxx> April 16th 2006
+# Modified by Marcus Griep <marcus@xxxxxxxx> June 16 2009
+# May be distributed under the same terms as Tor itself
+
+
+# Define and ensure we have tsocks
+# XXX: what if we don't have which?
+TORSOCKS="`which torsocks`"
+PROG=
+VERBOSE=
+
+usage () {
+ echo "Usage: $0 [-hv] <command> [<options>...]"
+}
+
+not_found () {
+ echo "ERROR: $1 cannot be found in PATH." >&2
+ exit 1
+}
+
+set_id () {
+ echo "ERROR: $1 is set${2}id. usewithtor will not work on a set${2}id executable." >&2
+ exit 1
+}
+
+# Check for any argument list
+if [ "$#" = 0 ]; then
+ usage >&2
+ exit 1
+fi
+
+while [ "$1" ]; do
+ case "$1" in
+ -h|--h*)
+ usage
+ exit 0
+ ;;
+ -v|--v*)
+ VERBOSE=YesPlease
+ shift
+ ;;
+ *)
+ break;
+ esac
+done
+
+if ! which "$1" >/dev/null 2>&1; then
+ not_found $1
+elif [ -u `which "$1"` ]; then
+ set_id $1 u
+elif [ -g `which "$1"` ]; then
+ set_id $1 g
+fi
+
+if [ -x "$TORSOCKS" ]; then
+ PROG=torsocks
+else
+ echo "$0: Unable to find torsocks in PATH." >&2
+ echo " Perhaps you haven't installed it?" >&2
+ exit 1
+fi
+
+if [ "$VERBOSE" ]; then
+ echo "We're armed with the following torsocks: $TORSOCKS"
+ echo "We're attempting to use $PROG for all tor action."
+fi
+
+if [ "$PROG" = "torsocks" ]; then
+ # Define our torsocks config file
+ TORSOCKS_CONF_FILE="@CONFDIR@/torsocks.conf"
+ export TORSOCKS_CONF_FILE
+
+ # Check that we've got a torsocks config file
+ if [ -r "$TORSOCKS_CONF_FILE" ]; then
+ exec torsocks "$@"
+ else
+ echo "$0: Missing torsocks configuration file \"$TORSOCKS_CONF_FILE\" - torsocks will use defaults sensible for Tor." >&2
+ exec torsocks "$@"
+ fi
+fi
+
+# We should have hit an exec. If we get here, we didn't exec
+echo "$0: failed to exec $PROG $@" >&2
+exit 1
diff --git a/src/common.c b/src/common.c
deleted file mode 100644
index 8fe3303..0000000
--- a/src/common.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/***************************************************************************
- * *
- * Copyright (C) 2000-2008 Shaun Clowes <delius@xxxxxxxxxxx> *
- * Copyright (C) 2008-2011 Robert Hogan <robert@xxxxxxxxxxxxxxx> *
- * *
- * 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. *
- * *
- * Some code taken from Tor: *
- * Copyright (c) 2003, Roger Dingledine *
- * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. *
- * Copyright (c) 2007-2008, The Tor Project, Inc. *
- * *
- ***************************************************************************/
-/*
-
- commmon.c - Common routines for the torsocks package
-
-*/
-
-#include <config.h>
-#include <stdio.h>
-#include <netdb.h>
-#include <stdarg.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-
-#include "common.h"
-
-/* Globals */
-int loglevel = MSGERR; /* The default logging level is to only log
- error messages */
-char logfilename[256]; /* Name of file to which log messages should
- be redirected */
-FILE *logfile = NULL; /* File to which messages should be logged */
-int logstamp = 0; /* Timestamp (and pid stamp) messages */
-
-
-/**
- * Read a 16-bit value beginning at <b>cp</b>. Equivalent to
- * *(uint16_t*)(cp), but will not cause segfaults on platforms that forbid
- * unaligned memory access.
- */
-uint16_t
-get_uint16(const char *cp)
-{
- uint16_t v;
- memcpy(&v,cp,2);
- return v;
-}
-/**
- * Read a 32-bit value beginning at <b>cp</b>. Equivalent to
- * *(uint32_t*)(cp), but will not cause segfaults on platforms that forbid
- * unaligned memory access.
- */
-uint32_t
-get_uint32(const char *cp)
-{
- uint32_t v;
- memcpy(&v,cp,4);
- return v;
-}
-/**
- * Set a 16-bit value beginning at <b>cp</b> to <b>v</b>. Equivalent to
- * *(uint16_t)(cp) = v, but will not cause segfaults on platforms that forbid
- * unaligned memory access. */
-void
-set_uint16(char *cp, uint16_t v)
-{
- memcpy(cp,&v,2);
-}
-/**
- * Set a 32-bit value beginning at <b>cp</b> to <b>v</b>. Equivalent to
- * *(uint32_t)(cp) = v, but will not cause segfaults on platforms that forbid
- * unaligned memory access. */
-void
-set_uint32(char *cp, uint32_t v)
-{
- memcpy(cp,&v,4);
-}
-
-unsigned int resolve_ip(char *host, int showmsg, int allownames) {
- struct hostent *new;
- unsigned int hostaddr;
- struct in_addr *ip;
-
- if ((hostaddr = inet_addr(host)) == (unsigned int) -1) {
- /* We couldn't convert it as a numerical ip so */
- /* try it as a dns name */
- if (allownames) {
- #ifdef HAVE_GETHOSTBYNAME
- if ((new = gethostbyname(host)) == (struct hostent *) 0) {
- #endif
- return(0);
- #ifdef HAVE_GETHOSTBYNAME
- } else {
- ip = ((struct in_addr *) * new->h_addr_list);
- hostaddr = ip -> s_addr;
- if (showmsg)
- printf("Connecting to %s...\n", inet_ntoa(*ip));
- }
- #endif
- } else
- return(0);
- }
-
- return (hostaddr);
-}
-
-/* Set logging options, the options are as follows: */
-/* level - This sets the logging threshold, messages with */
-/* a higher level (i.e lower importance) will not be */
-/* output. For example, if the threshold is set to */
-/* MSGWARN a call to log a message of level MSGDEBUG */
-/* would be ignored. This can be set to -1 to disable */
-/* messages entirely */
-/* filename - This is a filename to which the messages should */
-/* be logged instead of to standard error */
-/* timestamp - This indicates that messages should be prefixed */
-/* with timestamps (and the process id) */
-void set_log_options(int level, char *filename, int timestamp) {
-
- loglevel = level;
- if (loglevel < MSGERR)
- loglevel = MSGNONE;
-
- if (filename) {
- strncpy(logfilename, filename, sizeof(logfilename));
- logfilename[sizeof(logfilename) - 1] = '\0';
- }
-
- logstamp = timestamp;
-}
-
-/* Count the bits in a netmask. This is a little bit buggy; it assumes
- all the zeroes are on the right... */
-
-int count_netmask_bits(uint32_t mask)
-{
- int i;
- int nbits = 0;
-
- for(i=0; i<32; i++) {
- if((mask >> i) & 1) {
- nbits++;
- }
- }
- mask = ~mask;
- mask = ntohl(mask);
- if(mask & (mask+1)) {
- return -1; /* Noncontiguous */
- }
- return nbits;
-}
-
-void show_msg(int level, const char *fmt, ...) {
- va_list ap;
- int saveerr;
- extern char *torsocks_progname;
- char timestring[20];
- time_t timestamp;
-
- if ((loglevel == MSGNONE) || (level > loglevel))
- return;
-
- if (!logfile) {
- if (logfilename[0]) {
- logfile = fopen(logfilename, "a");
- if (logfile == NULL) {
- logfile = stderr;
- show_msg(MSGERR, "Could not open log file, %s, %s\n",
- logfilename, strerror(errno));
- }
- } else
- logfile = stderr;
- }
-
- if (logstamp) {
- timestamp = time(NULL);
- strftime(timestring, sizeof(timestring), "%H:%M:%S",
- localtime(×tamp));
- fprintf(logfile, "%s ", timestring);
- }
-
- fputs(torsocks_progname, logfile);
-
- if (logstamp) {
- fprintf(logfile, "(%d)", getpid());
- }
-
- fputs(": ", logfile);
-
- va_start(ap, fmt);
-
- /* Save errno */
- saveerr = errno;
-
- vfprintf(logfile, fmt, ap);
-
- fflush(logfile);
-
- errno = saveerr;
-
- va_end(ap);
-}
-
diff --git a/src/common.h b/src/common.h
deleted file mode 100644
index f84a2f7..0000000
--- a/src/common.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/***************************************************************************
- * *
- * Copyright (C) 2000-2008 Shaun Clowes <delius@xxxxxxxxxxx> *
- * Copyright (C) 2008-2011 Robert Hogan <robert@xxxxxxxxxxxxxxx> *
- * *
- * 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. *
- ***************************************************************************/
-
-/* Common functions provided in common.c */
-/* GCC has several useful attributes. */
-#include <sys/types.h>
-
-#if defined(__GNUC__) && __GNUC__ >= 3
-#define ATTR_NORETURN __attribute__((noreturn))
-#define ATTR_PURE __attribute__((pure))
-#define ATTR_CONST __attribute__((const))
-#define ATTR_MALLOC __attribute__((malloc))
-#define ATTR_NORETURN __attribute__((noreturn))
-#define ATTR_NONNULL(x) __attribute__((nonnull x))
-/** Macro: Evaluates to <b>exp</b> and hints the compiler that the value
- * of <b>exp</b> will probably be true. */
-#define PREDICT_LIKELY(exp) __builtin_expect((exp), 1)
-/** Macro: Evaluates to <b>exp</b> and hints the compiler that the value
- * of <b>exp</b> will probably be false. */
-#define PREDICT_UNLIKELY(exp) __builtin_expect((exp), 0)
-#else
-#define ATTR_NORETURN
-#define ATTR_PURE
-#define ATTR_CONST
-#define ATTR_MALLOC
-#define ATTR_NORETURN
-#define ATTR_NONNULL(x)
-#define PREDICT_LIKELY(exp) (exp)
-#define PREDICT_UNLIKELY(exp) (exp)
-#endif
-
-/** Try to find the symbol that is either m or __m.
- * If one of them exists, in that order, then save its address in r,
- * otherwise we want to print a message at log level l stating that
- * we could not find it.
- */
-#define torsocks_find_library(m,l,r) \
- do { \
- char * dl_error_msg = ""; \
- char * dl_error_msg2 = ""; \
- dlerror(); \
- if ((r = dlsym(RTLD_NEXT, m)) == NULL) { \
- dl_error_msg = dlerror(); \
- if (dl_error_msg != NULL) { \
- dl_error_msg = strdup(dl_error_msg); \
- } \
- if ((r = dlsym(RTLD_NEXT, "__" m)) == NULL) { \
- dl_error_msg2 = dlerror(); \
- show_msg(l, "WARNING: The symbol %s() was not found in any shared " \
- "library with the reported error: %s!\n" \
- " Also, we failed to find the symbol %s() with the reported error:" \
- " %s\n", m, (dl_error_msg ? dl_error_msg : "Not Found"), \
- "__"m, (dl_error_msg2 ? dl_error_msg2 : "Not Found")); \
- } \
- if (dl_error_msg) \
- free(dl_error_msg); \
- } \
- } while (0)
-
-uint16_t get_uint16(const char *cp) ATTR_PURE ATTR_NONNULL((1));
-uint32_t get_uint32(const char *cp) ATTR_PURE ATTR_NONNULL((1));
-void set_uint16(char *cp, uint16_t v) ATTR_NONNULL((1));
-void set_uint32(char *cp, uint32_t v) ATTR_NONNULL((1));
-
-int is_internal_IP(uint32_t ip, int for_listening) ATTR_PURE;
-int parse_addr_port(int severity, const char *addrport, char **address,
- uint32_t *addr, uint16_t *port_out);
-
-void set_log_options(int, char *, int);
-void show_msg(int level, const char *, ...);
-int count_netmask_bits(uint32_t mask);
-unsigned int resolve_ip(char *, int, int);
-
-#define MSGNONE -1
-#define MSGERR 0
-#define MSGWARN 1
-#define MSGTEST 2
-#define MSGNOTICE 3
-#define MSGDEBUG 3
-
-/* Required by some BSDs */
-#ifndef MAP_ANONYMOUS
-#ifdef MAP_ANON
-#define MAP_ANONYMOUS MAP_ANON
-#endif
-#endif
diff --git a/src/darwin_warts.c b/src/darwin_warts.c
deleted file mode 100644
index 65bdd04..0000000
--- a/src/darwin_warts.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/***************************************************************************
- * *
- * Copyright (C) 2010 Alex Rosenberg <alex@xxxxxxxxxxxxx> *
- * *
- * 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. *
- ***************************************************************************/
-
-/* Mac OS X 10.6 forces any function named "select" to be named "_select$1050"
- * in the output to the assembler. We need to patch select as well, so this
- * isolated code exists without tripping over the Darwin header that causes the
- * probkem.
- */
-
-#if defined(__APPLE__) || defined(__darwin__)
-
-#include <AvailabilityMacros.h>
-
-#if defined(MAC_OS_X_VERSION_10_6)
-
-#include <stddef.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <dlfcn.h>
-#include <string.h>
-#include <errno.h>
-#include "common.h"
-
-#define SELECT_SIGNATURE int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout
-#define SELECT_ARGNAMES n, readfds, writefds, exceptfds, timeout
-
-/* forward declare opaque structures instead of bringing in real Darwin decls. */
-typedef struct fd_set fd_set;
-struct timeval;
-
-int (*realselect)(SELECT_SIGNATURE);
-int torsocks_select_guts(SELECT_SIGNATURE, int (*original_select)(SELECT_SIGNATURE));
-
-int select(SELECT_SIGNATURE) {
- if (!realselect) {
- torsocks_find_library("select", MSGERR, realselect);
- }
- return torsocks_select_guts(SELECT_ARGNAMES, realselect);
-}
-
-#endif /* 10.6 */
-#endif /* darwin */
diff --git a/src/dead_pool.c b/src/dead_pool.c
deleted file mode 100644
index 13e5740..0000000
--- a/src/dead_pool.c
+++ /dev/null
@@ -1,805 +0,0 @@
-/***************************************************************************
- * *
- * Copyright (C) 2005 Total Information Security Ltd. *
- * Copyright (C) 2008-2011 Robert Hogan <robert@xxxxxxxxxxxxxxx> *
- * *
- * 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. *
- ***************************************************************************/
-
-#include <stdio.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-
-#include "common.h"
-#include "dead_pool.h"
-
-int store_pool_entry(dead_pool *pool, char *hostname, struct in_addr *addr);
-void get_next_dead_address(dead_pool *pool, uint32_t *result);
-
-static int
-do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport,
- uint32_t *result_addr, const void *addr,
- int version, int reverse, char **result_hostname);
-
-/* Compares the last strlen(s2) characters of s1 with s2. Returns as for
- strcasecmp. */
-static int
-strcasecmpend(const char *s1, const char *s2)
-{
- size_t n1 = strlen(s1), n2 = strlen(s2);
- if (n2>n1) /* then they can't be the same; figure out which is bigger */
- return strcasecmp(s1,s2);
- else
- return strncasecmp(s1+(n1-n2), s2, n2);
-}
-
-dead_pool *
-init_pool(unsigned int pool_size, struct in_addr deadrange_base,
- struct in_addr deadrange_mask, char *sockshost, uint16_t socksport)
-{
- unsigned int i, deadrange_size, deadrange_width;
- int deadrange_bits;
- struct in_addr socks_server;
- dead_pool *newpool = NULL;
-
- /* Count bits in netmask and determine deadrange width. */
- deadrange_bits = count_netmask_bits(deadrange_mask.s_addr);
- if(deadrange_bits == -1) {
- show_msg(MSGERR, "init_pool: invalid netmask for deadrange\n");
- return NULL;
- }
- deadrange_width = 32 - deadrange_bits;
-
- show_msg(MSGDEBUG, "deadrange width is %d bits\n", deadrange_width);
-
- /* Now work out how many IPs are available in the deadrange and check
- that this number makes sense. If the deadpool is bigger than the
- deadrange we shrink the pool. */
-
- for(i=0, deadrange_size = 1; i < deadrange_width; i++) {
- deadrange_size *= 2;
- }
-
- if(deadrange_size < pool_size) {
- show_msg(MSGWARN, "tordns cache size was %d, but deadrange size is %d: "
- "shrinking pool size to %d entries\n", pool_size,
- deadrange_size, deadrange_size);
- pool_size = deadrange_size;
- }
- if(pool_size < 1) {
- show_msg(MSGERR, "tordns cache size is 0, disabling tordns\n");
- return NULL;
- }
-
- /* Allocate space for the dead_pool structure */
- newpool = (dead_pool *) mmap(0, sizeof(dead_pool),
- PROT_READ | PROT_WRITE,
- MAP_SHARED | MAP_ANONYMOUS, -1, 0);
- if(!newpool) {
- show_msg(MSGERR, "init_pool: unable to mmap deadpool "
- "(tried to map %d bytes)\n", sizeof(dead_pool));
- return NULL;
- }
-
- show_msg(MSGDEBUG, "init_pool: sockshost %s \n", sockshost);
-
- /* Initialize the dead_pool structure */
-#ifdef HAVE_INET_ATON
- inet_aton(sockshost, &socks_server);
-#elif defined(HAVE_INET_ADDR)
- socks_server.s_addr = inet_addr(sockshost);
-#endif
- newpool->sockshost = ntohl(socks_server.s_addr);
- newpool->socksport = socksport;
- newpool->deadrange_base = ntohl(deadrange_base.s_addr);
- newpool->deadrange_mask = ntohl(deadrange_mask.s_addr);
- newpool->deadrange_size = deadrange_size;
- newpool->write_pos = 0;
- newpool->dead_pos = 0;
- newpool->n_entries = pool_size;
-
- /* Allocate space for the entries */
- newpool->entries = (pool_ent *) mmap(0, newpool->n_entries * sizeof(pool_ent),
- PROT_READ | PROT_WRITE,
- MAP_SHARED | MAP_ANONYMOUS, -1, 0);
- if(!newpool->entries) {
- munmap((void *)newpool, sizeof(dead_pool));
- show_msg(MSGERR, "init_pool: unable to mmap deadpool entries "
- "(tried to map %d bytes)\n",
- newpool->n_entries * sizeof(pool_ent));
- return NULL;
- }
-
- /* Initialize the entries */
- for(i=0; i < newpool->n_entries; i++) {
- newpool->entries[i].ip = -1;
- newpool->entries[i].name[0] = '\0';
- }
-
- return newpool;
-}
-
-int
-is_dead_address(dead_pool *pool, uint32_t addr)
-{
- uint32_t haddr = ntohl(addr);
- if(pool == NULL) {
- return 0;
- }
- return (pool->deadrange_base == (haddr & pool->deadrange_mask));
-}
-
-void
-get_next_dead_address(dead_pool *pool, uint32_t *result)
-{
- *result = htonl(pool->deadrange_base + pool->dead_pos++);
- if(pool->dead_pos >= pool->deadrange_size) {
- pool->dead_pos = 0;
- }
-}
-
-int
-store_pool_entry(dead_pool *pool, char *hostname, struct in_addr *addr)
-{
- int position = pool->write_pos;
- int oldpos;
- int rc;
- uint32_t intaddr;
- char *result_hostname;
-
- show_msg(MSGDEBUG, "store_pool_entry: storing '%s'\n", hostname);
- show_msg(MSGDEBUG, "store_pool_entry: write pos is: %d\n", pool->write_pos);
-
- /* Check to see if name already exists in pool */
- oldpos = search_pool_for_name(pool, hostname);
- if(oldpos != -1){
- show_msg(MSGDEBUG, "store_pool_entry: not storing (entry exists)\n");
- addr->s_addr = pool->entries[oldpos].ip;
- return oldpos;
- }
-
- /* If this is a .onion host, then we return a bogus ip from our deadpool,
- otherwise we try to resolve it and store the 'real' IP */
- if(strcasecmpend(hostname, ".onion") == 0) {
- get_next_dead_address(pool, &pool->entries[position].ip);
- } else {
- rc = do_resolve(hostname, pool->sockshost, pool->socksport, &intaddr, 0,
- 4 /*SOCKS5*/, 0 /*Reverse*/, &result_hostname);
-
- if(rc != 0) {
- show_msg(MSGWARN, "failed to resolve: %s\n", hostname);
- return -1;
- }
- if(is_dead_address(pool, intaddr)) {
- show_msg(MSGERR, "resolved %s -> %d (deadpool address) IGNORED\n");
- return -1;
- }
- pool->entries[position].ip = intaddr;
- }
-
- strncpy(pool->entries[position].name, hostname, 255);
- pool->entries[position].name[255] = '\0';
- pool->write_pos++;
- if(pool->write_pos >= pool->n_entries) {
- pool->write_pos = 0;
- }
- addr->s_addr = pool->entries[position].ip;
-
- show_msg(MSGDEBUG, "store_pool_entry: stored entry in slot '%d'\n", position);
-
- return position;
-}
-
-int
-search_pool_for_name(dead_pool *pool, const char *name)
-{
- unsigned int i;
- for(i=0; i < pool->n_entries; i++){
- if(strcmp(name, pool->entries[i].name) == 0){
- return i;
- }
- }
- return -1;
-}
-
-char *
-get_pool_entry(dead_pool *pool, struct in_addr *addr)
-{
- unsigned int i;
- uint32_t intaddr = addr->s_addr;
-
- if(pool == NULL) {
- return NULL;
- }
-
- show_msg(MSGDEBUG, "get_pool_entry: searching for: %s\n", inet_ntoa(*addr));
- for(i=0; i<pool->n_entries; i++) {
- if(intaddr == pool->entries[i].ip) {
- show_msg(MSGDEBUG, "get_pool_entry: found: %s\n", pool->entries[i].name);
- return pool->entries[i].name;
- }
- }
- show_msg(MSGDEBUG, "get_pool_entry: address not found\n");
-
- return NULL;
-}
-
-static int
-build_socks4a_resolve_request(char **out,
- const char *username,
- const char *hostname)
-{
- size_t len;
- uint16_t port = htons(0); /* port: 0. */
- uint32_t addr = htonl(0x00000001u); /* addr: 0.0.0.1 */
-
- len = 8 + strlen(username) + 1 + strlen(hostname) + 1;
- *out = malloc(len);
- (*out)[0] = 4; /* SOCKS version 4 */
- (*out)[1] = '\xF0'; /* Command: resolve. */
-
- memcpy((*out)+2, &port, sizeof(port));
- memcpy((*out)+4, &addr, sizeof(addr));
- strcpy((*out)+8, username);
- strcpy((*out)+8+strlen(username)+1, hostname);
-
- return len;
-}
-
-static int
-build_socks5_resolve_ptr_request(char **out, const void *_addr)
-{
- size_t len;
- const struct in_addr *addr=_addr;
-
- len = 12;
- *out = malloc(len);
- (*out)[0] = 5; /* SOCKS version 5 */
- (*out)[1] = '\xF1'; /* Command: reverse resolve.
- see doc/socks-extensions.txt*/
- (*out)[2] = '\x00'; /* RSV */
- (*out)[3] = '\x01'; /* ATYP: IP V4 address: X'01' */
-
- set_uint32((*out)+4, addr->s_addr);/*IP*/
- set_uint16((*out)+4+4, 0); /* port */
-
- return len;
-}
-
-#define RESPONSE_LEN 8
-#define SOCKS5_LEN 4
-#define METHODRESPONSE_LEN 2
-
-static int
-parse_socks4a_resolve_response(const char *response, size_t len,
- uint32_t *addr_out)
-{
- uint8_t status;
- uint16_t port;
-
- if (len < RESPONSE_LEN) {
- show_msg(MSGWARN,"Truncated socks response.\n");
- return -1;
- }
- if (((uint8_t)response[0])!=0) { /* version: 0 */
- show_msg(MSGWARN,"Nonzero version in socks response: bad format.\n");
- return -1;
- }
- status = (uint8_t)response[1];
-
- memcpy(&port, response+2, sizeof(port));
- if (port!=0) { /* port: 0 */
- show_msg(MSGWARN,"Nonzero port in socks response: bad format.\n");
- return -1;
- }
- if (status != 90) {
- show_msg(MSGWARN,"Bad status: socks request failed.\n");
- return -1;
- }
-
- memcpy(addr_out, response+4, sizeof(*addr_out));
-
- return 0;
-}
-
-static int
-parse_socks5_resolve_ptr_response(int s,const char *response, size_t len,
- uint32_t *result_addr, char ***result_hostname)
-{
- char reply_buf[4];
- int r;
-
- len=0;
- while (len < SOCKS5_LEN) {
- r = recv(s, reply_buf+len, SOCKS5_LEN-len, 0);
- if (r==0) {
- show_msg(MSGWARN, "do_resolve: EOF while reading SOCKS5 response\n");
- return -1;
- }
- if (r<0) {
- show_msg(MSGWARN, "do_resolve: error reading SOCKS5 response\n");
- return -1;
- }
- len += r;
- }
-
- if (reply_buf[0] != 5) {
- show_msg(MSGWARN, "Bad SOCKS5 reply version.");
- return -1;
- }
- if (reply_buf[1] != 0) {
- show_msg(MSGWARN,"Got status response '%u': SOCKS5 request failed.",
- (unsigned)reply_buf[1]);
- return -1;
- }
- if (reply_buf[3] == 1) {
- /* IPv4 address */
- len=0;
- while (len < SOCKS5_LEN) {
- r = recv(s, reply_buf+len, SOCKS5_LEN-len, 0);
- if (r==0) {
- show_msg(MSGWARN, "do_resolve: EOF while reading SOCKS5 response\n");
- return -1;
- }
- if (r<0) {
- show_msg(MSGWARN, "do_resolve: error reading address in SOCKS5 response\n");
- return -1;
- }
- len += r;
- }
- *result_addr = ntohl(get_uint32(reply_buf));
- } else if (reply_buf[3] == 3) {
- size_t result_len;
- len=0;
- while (len < 1) {
- r = recv(s, reply_buf+len, 1-len, 0);
- if (r==0) {
- show_msg(MSGWARN, "do_resolve: EOF while reading SOCKS5 response\n");
- return -1;
- }
- if (r<0) {
- show_msg(MSGWARN, "do_resolve: error reading address length in SOCKS5 response\n");
- return -1;
- }
- len += r;
- }
- result_len = *(uint8_t*)(reply_buf);
- **result_hostname = malloc(result_len+1);
- len=0;
- while (len < (int) result_len) {
- r = recv(s, **result_hostname+len, result_len-len, 0);
- if (r==0) {
- show_msg(MSGWARN, "do_resolve: EOF while reading SOCKS5 response\n");
- return -1;
- }
- if (r<0) {
- show_msg(MSGWARN, "do_resolve: error reading hostname in SOCKS5 response\n");
- return -1;
- }
- len += r;
- }
-
- (**result_hostname)[result_len] = '\0';
- }
-
- return 0;
-}
-
-static int
-do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport,
- uint32_t *result_addr, const void *addr,
- int version, int reverse, char **result_hostname)
-{
- int s;
- struct sockaddr_in socksaddr;
- char *req, *cp=NULL;
- int r, len, hslen;
- char response_buf[RESPONSE_LEN];
- const char *handshake="\x05\x01\x00";
-
- show_msg(MSGDEBUG, "do_resolve: resolving %s\n", hostname);
-
- /* Create SOCKS connection */
- s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (s<0) {
- show_msg(MSGWARN, "do_resolve: problem creating socket\n");
- return -1;
- }
-
- /* Connect to SOCKS server */
- memset(&socksaddr, 0, sizeof(socksaddr));
- socksaddr.sin_family = AF_INET;
- socksaddr.sin_port = htons(socksport);
- socksaddr.sin_addr.s_addr = htonl(sockshost);
- if (realconnect(s, (struct sockaddr*)&socksaddr, sizeof(socksaddr))) {
- show_msg(MSGWARN, "do_resolve: error connecting to SOCKS server\n");
- realclose(s);
- return -1;
- }
-
- /* If a SOCKS5 connection, perform handshake */
- if (version == 5) {
- char method_buf[2];
- hslen=3;
- while (hslen) {
- r = send(s, handshake, hslen, 0);
- if (r<0) {
- show_msg(MSGWARN, "do_resolve: error sending SOCKS5 method list.\n");
- realclose(s);
- return -1;
- }
- hslen -= r;
- handshake += r;
- }
-
- len = 0;
- while (len < METHODRESPONSE_LEN) {
- r = recv(s, method_buf+len, METHODRESPONSE_LEN-len, 0);
- if (r==0) {
- show_msg(MSGWARN, "do_resolve: EOF while reading SOCKS response\n");
- realclose(s);
- return -1;
- }
- if (r<0) {
- show_msg(MSGWARN, "do_resolve: error reading SOCKS response\n");
- realclose(s);
- return -1;
- }
- len += r;
- }
-
- if (method_buf[0] != '\x05') {
- show_msg(MSGWARN, "Unrecognized socks version: %u",
- (unsigned)method_buf[0]);
- realclose(s);
- return -1;
- }
- if (method_buf[1] != '\x00') {
- show_msg(MSGWARN, "Unrecognized socks authentication method: %u",
- (unsigned)method_buf[1]);
- realclose(s);
- return -1;
- }
- }
-
- /* Create SOCKS request */
- if (reverse) {
- if ((len = build_socks5_resolve_ptr_request(&req, addr))<0) {
- show_msg(MSGWARN, "do_resolve: error generating reverse SOCKS request\n");
- realclose(s);
- return -1;
- }
- }else{
- if ((len = build_socks4a_resolve_request(&req, "", hostname))<0) {
- show_msg(MSGWARN, "do_resolve: error generating SOCKS request\n");
- realclose(s);
- return -1;
- }
- }
-
- /* Send SOCKS request */
- cp = req;
- while (len) {
- r = send(s, cp, len, 0);
- if (r<0) {
- show_msg(MSGWARN, "do_resolve: error sending SOCKS request\n");
- free(req);
- realclose(s);
- return -1;
- }
- len -= r;
- cp += r;
- }
- free(req);
-
- /* Handle SOCKS Response */
- if (reverse) {
- if (parse_socks5_resolve_ptr_response(s, response_buf, RESPONSE_LEN,
- result_addr, &result_hostname) < 0){
- show_msg(MSGWARN, "do_resolve: error parsing SOCKS response\n");
- realclose(s);
- return -1;
- }
- }else{
- /* Process SOCKS response */
- len = 0;
- while (len < RESPONSE_LEN) {
- r = recv(s, response_buf+len, RESPONSE_LEN-len, 0);
- if (r==0) {
- show_msg(MSGWARN, "do_resolve: EOF while reading SOCKS response\n");
- realclose(s);
- return -1;
- }
- if (r<0) {
- show_msg(MSGWARN, "do_resolve: error reading SOCKS response\n");
- realclose(s);
- return -1;
- }
- len += r;
- }
- realclose(s);
-
- /* Parse SOCKS response */
- if (parse_socks4a_resolve_response(response_buf, RESPONSE_LEN, result_addr) < 0){
- show_msg(MSGWARN, "do_resolve: error parsing SOCKS response\n");
- return -1;
- }
- }
-
-
- show_msg(MSGDEBUG, "do_resolve: success\n");
-
- return 0;
-}
-
-struct hostent *
-our_gethostbyaddr(dead_pool *pool, const void *_addr, socklen_t len, int type)
-{
- const struct in_addr *addr=_addr;
- static struct hostent he;
- uint32_t intaddr=0;
- char *result_hostname=NULL;
- int rc=0;
- static char *addrs[2];
- static char *aliases[2];
-
- rc = do_resolve("", pool->sockshost, pool->socksport, &intaddr, addr,
- 5 /*SOCKS5*/, 1 /*Reverse*/, &result_hostname);
-
-
- if(rc != 0) {
- show_msg(MSGWARN, "failed to reverse resolve: %s\n",
- inet_ntoa(*((struct in_addr *)addr)));
- result_hostname=NULL;
- addrs[0] = NULL;
- addrs[1] = NULL;
- }else{
- addrs[0] = (char *)addr;
- addrs[1] = NULL;
- }
-
- if (result_hostname)
- he.h_name = result_hostname;
- else
- he.h_name = inet_ntoa(*((struct in_addr *)addr));
-
- aliases[0] = NULL;
- aliases[1] = NULL;
-
- he.h_aliases = aliases;
- he.h_length = len;
- he.h_addrtype = type;
- he.h_addr_list = addrs;
-
- if (result_hostname)
- show_msg(MSGTEST, "our_gethostbyaddr: resolved '%s' to: '%s'\n",
- inet_ntoa(*((struct in_addr *)he.h_addr)), result_hostname);
-
- return &he;
-
-}
-
-struct hostent *
-our_gethostbyname(dead_pool *pool, const char *name)
-{
- int pos;
- static struct in_addr addr;
- static struct hostent he;
- static char *addrs[2];
-
- show_msg(MSGTEST, "our_gethostbyname: '%s' requested\n", name);
-
- pos = store_pool_entry(pool,(char *) name, &addr);
- if(pos == -1) {
- h_errno = HOST_NOT_FOUND;
- return NULL;
- }
-
- addrs[0] = (char *)&addr;
- addrs[1] = NULL;
-
- he.h_name = pool->entries[pos].name;
- he.h_aliases = NULL;
- he.h_length = 4;
- he.h_addrtype = AF_INET;
- he.h_addr_list = addrs;
-
- show_msg(MSGDEBUG, "our_gethostbyname: resolved '%s' to: '%s'\n",
- name, inet_ntoa(*((struct in_addr *)he.h_addr)));
-
- return &he;
-}
-
-static struct hostent *
-alloc_hostent(int af)
-{
- struct hostent *he = NULL;
- char **addr_list = NULL;
- void *addr = NULL;
- char **aliases = NULL;
-
- if(af != AF_INET && af != AF_INET6) {
- return NULL;
- }
-
- /* Since the memory we allocate here will be free'd by freehostent and
- that function is opaque to us, it's likely that we'll leak a little
- bit of memory here. */
-
- he = malloc(sizeof(struct hostent));
- addr_list = malloc(2 * sizeof(char *));
- if(af == AF_INET6) {
- addr = malloc(sizeof(struct in6_addr));
- } else {
- addr = malloc(sizeof(struct in_addr));
- }
- aliases = malloc(sizeof(char *));
-
- if(he == NULL || addr_list == NULL || addr == NULL || aliases == NULL) {
- if(he)
- free(he);
- if(addr_list)
- free(addr_list);
- if(addr)
- free(addr);
- if(aliases)
- free(aliases);
- }
-
- he->h_name = NULL;
- he->h_addr_list = addr_list;
- he->h_addr_list[0] = addr;
- he->h_addr_list[1] = NULL;
- he->h_aliases = aliases;
- he->h_aliases[0] = NULL;
- he->h_length = af == AF_INET ? 4 : 16;
- he->h_addrtype = af;
-
- return he;
-}
-
-/* On Linux, there's no freehostent() anymore; we might as well implement
- this ourselves. */
-
-static void
-free_hostent(struct hostent *he)
-{
- int i;
- if(he->h_name) {
- free(he->h_name);
- }
- if(he->h_aliases) {
- for(i=0; he->h_aliases[i] != NULL; i++) {
- free(he->h_aliases[i]);
- }
- free(he->h_aliases);
- }
- if(he->h_addr_list) {
- free(he->h_addr_list);
- }
- free(he);
-}
-
-int
-our_getaddrinfo(dead_pool *pool, const char *node, const char *service,
- void *hints, void *res)
-{
- int pos;
- struct in_addr addr;
- char *ipstr;
- int ret;
-
- /* If "node" looks like a dotted-decimal ip address, then just call
- the real getaddrinfo; otherwise we'll need to get an address from
- our pool. */
-
- /* TODO: work out what to do with AF_INET6 requests */
-
-#ifdef HAVE_INET_ATON
- if(node && inet_aton(node, &addr) == 0 && memcmp(node,"*",1)) {
-#elif defined(HAVE_INET_ADDR)
- /* If we're stuck with inet_addr, then getaddrinfo() won't work
- properly with 255.255.255.255 (= -1). There's not much we can
- do about this */
- in_addr_t is_valid;
- is_valid = inet_addr(node);
- if(is_valid == -1) {
-#endif
- pos = store_pool_entry(pool, (char *) node, &addr);
- if(pos == -1) {
- return EAI_NONAME;
- } else {
- ipstr = strdup(inet_ntoa(addr));
- ret = realgetaddrinfo(ipstr, service, hints, res);
- free(ipstr);
- }
- } else {
- ret = realgetaddrinfo(node, service, hints, res);
- }
-
- show_msg(MSGTEST, "our_getaddrinfo: '%s' requested\n", service);
- return ret;
-}
-
-struct hostent *
-our_getipnodebyname(dead_pool *pool, const char *name, int af, int flags,
- int *error_num)
-{
- int pos;
- struct hostent *he = NULL;
- int want_4in6 = 0;
- char addr_convert_buf[80];
- struct in_addr pool_addr;
-
- if(af == AF_INET6) {
- /* Caller has requested an AF_INET6 address, and is not prepared to
- accept IPv4-mapped IPV6 addresses. There's nothing we can do to
- service their request. */
-#ifdef OPENBSD
- /* OpenBSD doesn't support the AI_V4MAPPED flag, so just return. */
- return NULL;
-#else
- if((flags & AI_V4MAPPED) == 0) {
- show_msg(MSGWARN, "getipnodebyname: asked for V6 addresses only, "
- "but torsocks can't handle that\n");
- *error_num = NO_RECOVERY;
- return NULL;
- } else {
- want_4in6 = 1;
- }
-#endif
- }
-
- pos = store_pool_entry(pool, (char *)name, &pool_addr);
- if(pos == -1) {
- *error_num = HOST_NOT_FOUND;
- return NULL;
- }
-
- he = alloc_hostent(af);
- if(he == NULL) {
- show_msg(MSGERR, "getipnodebyname: failed to allocate hostent\n");
- *error_num = NO_RECOVERY;
- return NULL;
- }
-
- if(want_4in6) {
- /* Convert the ipv4 address in *addr to an IPv4 in IPv6 mapped
- address. TODO: inet_ntoa() is thread-safe on Solaris but might
- not be on other platforms. */
- strcpy(addr_convert_buf, "::FFFF:");
- strcpy(addr_convert_buf+7, inet_ntoa(pool_addr));
- if(inet_pton(AF_INET6, addr_convert_buf, he->h_addr_list[0]) != 1) {
- show_msg(MSGERR, "getipnodebyname: inet_pton() failed!\n");
- free_hostent(he);
- *error_num = NO_RECOVERY;
- return NULL;
- }
- } else {
- ((struct in_addr *) he->h_addr_list[0])->s_addr = pool_addr.s_addr;
- }
- he->h_name = strdup(name);
-
- return he;
-}
-
-
diff --git a/src/dead_pool.h b/src/dead_pool.h
deleted file mode 100644
index d6e3e10..0000000
--- a/src/dead_pool.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/***************************************************************************
- * *
- * Copyright (C) 2005 Total Information Security Ltd. *
- * Copyright (C) 2008-2011 Robert Hogan <robert@xxxxxxxxxxxxxxx> *
- * *
- * 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. *
- ***************************************************************************/
-
-#ifndef _DEAD_POOL_H
-#define _DEAD_POOL_H
-
-#include <config.h>
-
-extern int (*realconnect)(CONNECT_SIGNATURE);
-extern int (*realclose)(CLOSE_SIGNATURE);
-extern int (*realgetaddrinfo)(GETADDRINFO_SIGNATURE);
-
-struct struct_pool_ent {
- unsigned int ip;
- char name[256];
-};
-
-typedef struct struct_pool_ent pool_ent;
-
-struct struct_dead_pool {
- pool_ent *entries; /* Points to array of pool entries */
- unsigned int n_entries; /* Number of entries in the deadpool */
- unsigned int deadrange_base; /* Deadrange start IP in host byte order */
- unsigned int deadrange_mask; /* Deadrange netmask in host byte order */
- unsigned int deadrange_size; /* Number of IPs in the deadrange */
- unsigned int write_pos; /* Next position to use in the pool array */
- unsigned int dead_pos; /* Next 'unused' deadpool IP */
- uint32_t sockshost;
- uint16_t socksport;
- char pad[2];
-};
-
-typedef struct struct_dead_pool dead_pool;
-
-dead_pool *init_pool(unsigned int deadpool_size, struct in_addr deadrange_base,
- struct in_addr deadrange_mask, char *sockshost, uint16_t socksport);
-int is_dead_address(dead_pool *pool, uint32_t addr);
-char *get_pool_entry(dead_pool *pool, struct in_addr *addr);
-int search_pool_for_name(dead_pool *pool, const char *name);
-struct hostent *our_gethostbyname(dead_pool *pool, const char *name);
-struct hostent *our_gethostbyaddr(dead_pool *pool, const void *addr,
- socklen_t len, int type);
-int our_getaddrinfo(dead_pool *pool, const char *node, const char *service,
- void *hints, void *res);
-struct hostent *our_getipnodebyname(dead_pool *pool, const char *name,
- int af, int flags, int *error_num);
-
-#endif /* _DEAD_POOL_H */
-
diff --git a/src/expansion_table.h b/src/expansion_table.h
deleted file mode 100644
index 14fabe1..0000000
--- a/src/expansion_table.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/***************************************************************************
- * *
- * Copyright (C) 2010 Alex Rosenberg <alex@xxxxxxxxxxxxx> *
- * Copyright (C) 2011 Robert Hogan <robert@xxxxxxxxxxxxxxx> *
- * *
- * 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. *
- ***************************************************************************/
-
-#undef FUNC
-#undef FUNCD
-#undef FUND32
-#undef FUNCD64
-
-#ifdef SUPPORT_RES_API
-#define RES_FUNC FUNC
-#define RES_FUNCD FUNCD
-#define RES_FUNCD32 FUNCD32
-#define RES_FUNCD64 FUNCD64
-#else
-#define RES_FUNC EMPTY_FUNC
-#define RES_FUNCD EMPTY_FUNC
-#define RES_FUNCD32 EMPTY_FUNC
-#define RES_FUNCD64 EMPTY_FUNC
-#endif /* SUPPORT_RES_API */
-
-#define DNS_FUNC FUNC
-#define DNS_FUNCD FUNCD
-#define DNS_FUNCD32 FUNCD32
-#define DNS_FUNCD64 FUNCD64
-
-#define EMPTY_FUNC(e,r,s,n,b,m)
-
-#if defined(__APPLE__) || defined(__darwin__)
-#ifndef DARWIN_EXPANSION
-#define DARWIN_EXPANSION PATCH_TABLE_EXPANSION
-#endif /* DARWIN_EXPANSION */
-#define FUNCD(e,r,s,n,b,m) DARWIN_EXPANSION(e,r,s,n,b,m)
-#if (__LP64__)
-#define FUNCD32(e,r,s,n,b,m) EMPTY_FUNC(e,r,s,n,b,m)
-#define FUNCD64(e,r,s,n,b,m) DARWIN_EXPANSION(e,r,s,n,b,m)
-/* This tests if we're building with 10.6 or later headers, not
- if we're running on 10.6. We'd rather do the latter. */
-#ifdef MAC_OS_X_VERSION_10_6
-#define FUNCD64_106(e,r,s,n,b,m) DARWIN_EXPANSION(e,r,s,n,b,m)
-#else
-#define FUNCD64_106(e,r,s,n,b,m) EMPTY_FUNC(e,r,s,n,b,m)
-#endif /* MAC_OS_X_VERSION_10_6 */
-#else
-#define FUNCD32(e,r,s,n,b,m) DARWIN_EXPANSION(e,r,s,n,b,m)
-#define FUNCD64(e,r,s,n,b,m) EMPTY_FUNC(e,r,s,n,b,m)
-#define FUNCD64_106(e,r,s,n,b,m) EMPTY_FUNC(e,r,s,n,b,m)
-#endif /* (__LP64__) */
-#else
-#define FUNCD(e,r,s,n,b,m) EMPTY_FUNC(e,r,s,n,b,m)
-#define FUNCD32(e,r,s,n,b,m) EMPTY_FUNC(e,r,s,n,b,m)
-#define FUNCD64(e,r,s,n,b,m) EMPTY_FUNC(e,r,s,n,b,m)
-#define FUNCD64_106(e,r,s,n,b,m) EMPTY_FUNC(e,r,s,n,b,m)
-#endif /* defined(__APPLE__) || defined(__darwin__) */
-#define FUNC(e,r,s,n,b,m) PATCH_TABLE_EXPANSION(e,r,s,n,b,m)
-
-/* dlsym return type SIG/ARGS C name base name asm name */
-/* res_init takes void, so we do that one manually. */
-/*RES_FUNC (ERR, int, RES_INIT_, res_init, res_init, "res_init") */
-RES_FUNC (ERR, int, RES_QUERY_, res_query, res_query, "res_query")
-RES_FUNC (ERR, int, RES_SEARCH_, res_search, res_search, "res_search")
-RES_FUNC (ERR, int, RES_SEND_, res_send, res_send, "res_send")
-RES_FUNC (ERR, int, RES_QUERYDOMAIN_, res_querydomain, res_querydomain, "res_querydomain")
-
-DNS_FUNC (ERR, struct hostent *, GETHOSTBYNAME_, gethostbyname, gethostbyname, "gethostbyname")
-DNS_FUNC (ERR, struct hostent *, GETHOSTBYADDR_, gethostbyaddr, gethostbyaddr, "gethostbyaddr")
-DNS_FUNC (ERR, int, GETADDRINFO_, getaddrinfo, getaddrinfo, "getaddrinfo")
-/* getipnodebyname is deprecated so do not report an error if it is not available.*/
-DNS_FUNC (WARN, struct hostent *, GETIPNODEBYNAME_, getipnodebyname, getipnodebyname, "getipnodebyname")
-
-DNS_FUNC (ERR, ssize_t, SENDTO_, sendto, sendto, "sendto")
-DNS_FUNCD32 (ERR, ssize_t, SENDTO_, sendto_unix2003, sendto, "sendto$UNIX2003")
-DNS_FUNCD32 (ERR, ssize_t, SENDTO_, sendto_nocancel_unix2003, sendto, "sendto$NOCANCEL$UNIX2003")
-DNS_FUNCD64 (ERR, ssize_t, SENDTO_, sendto_nocancel, sendto, "sendto$NOCANCEL")
-
-DNS_FUNC (ERR, ssize_t, SENDMSG_, sendmsg, sendmsg, "sendmsg")
-DNS_FUNCD32 (ERR, ssize_t, SENDMSG_, sendmsg_unix2003, sendmsg, "sendmsg$UNIX2003")
-DNS_FUNCD32 (ERR, ssize_t, SENDMSG_, sendmsg_nocancel_unix2003, sendmsg, "sendmsg$NOCANCEL$UNIX2003")
-DNS_FUNCD64 (ERR, ssize_t, SENDMSG_, sendmsg_nocancel, sendmsg, "sendmsg$NOCANCEL")
-
-FUNC (ERR, int, CONNECT_, connect, connect, "connect")
-FUNCD32 (ERR, int, CONNECT_, connect_unix2003, connect, "connect$UNIX2003")
-FUNCD32 (ERR, int, CONNECT_, connect_nocancel_unix2003, connect, "connect$NOCANCEL$UNIX2003")
-FUNCD64 (ERR, int, CONNECT_, connect_nocancel, connect, "connect$NOCANCEL")
-
-#if !(defined(__APPLE__) || defined(__darwin__) && defined(MAX_OS_X_VERSION_10_6))
-/* see darwin_warts.c */
-FUNC (ERR, int, SELECT_, select, select, "select")
-#endif
-FUNCD (ERR, int, SELECT_, select_darwinextsn, select, "select$DARWIN_EXTSN")
-FUNCD (ERR, int, SELECT_, select_darwinextsn_nocancel, select, "select$DARWIN_EXTSN$NOCANCEL")
-FUNCD32 (ERR, int, SELECT_, select_unix2003, select, "select$UNIX2003")
-FUNCD32 (ERR, int, SELECT_, select_nocancel_unix2003, select, "select$NOCANCEL$UNIX2003")
-FUNCD64 (ERR, int, SELECT_, select_nocancel, select, "select$NOCANCEL")
-FUNCD64_106 (ERR, int, SELECT_, select_1050, select, "select$1050")
-
-FUNC (ERR, int, POLL_, poll, poll, "poll")
-FUNCD32 (ERR, int, POLL_, poll_unix2003, poll, "poll$UNIX2003")
-FUNCD32 (ERR, int, POLL_, poll_nocancel_unix2003, poll, "poll$NOCANCEL$UNIX2003")
-FUNCD64 (ERR, int, POLL_, poll_nocancel, poll, "poll$NOCANCEL")
-
-FUNC (ERR, int, CLOSE_, close, close, "close")
-FUNCD32 (ERR, int, CLOSE_, close_unix2003, close, "close$UNIX2003")
-FUNCD32 (ERR, int, CLOSE_, close_nocancel_unix2003, close, "close$NOCANCEL$UNIX2003")
-FUNCD64 (ERR, int, CLOSE_, close_nocancel, close, "close$NOCANCEL")
-
-FUNC (ERR, int, GETPEERNAME_, getpeername, getpeername, "getpeername")
-FUNCD32 (ERR, int, GETPEERNAME_, getpeername_unix2003, getpeername, "getpeername$UNIX2003")
diff --git a/src/parser.c b/src/parser.c
deleted file mode 100644
index 8f24be6..0000000
--- a/src/parser.c
+++ /dev/null
@@ -1,872 +0,0 @@
-/***************************************************************************
- * *
- * Copyright (C) 2000-2008 Shaun Clowes <delius@xxxxxxxxxxx> *
- * Copyright (C) 2008-2011 Robert Hogan <robert@xxxxxxxxxxxxxxx> *
- * *
- * 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. *
- ***************************************************************************/
-/*
-
- parser.c - Parsing routines for torsocks.conf
-
-*/
-
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <config.h>
-
-#include "common.h"
-#include "parser.h"
-
-/* Global configuration variables */
-#define MAXLINE BUFSIZ /* Max length of conf line */
-static struct serverent *currentcontext = NULL;
-
-static int handle_line(struct parsedfile *, char *, int);
-static int check_server(struct serverent *);
-static int tokenize(char *, int, char *[]);
-static int handle_path(struct parsedfile *, int, int, char *[]);
-static int handle_endpath(struct parsedfile *, int, int);
-static int handle_reaches(int, char *);
-static int handle_server(struct parsedfile *, int, char *);
-static int handle_type(struct parsedfile *config, int, char *);
-static int handle_port(struct parsedfile *config, int, char *);
-static int handle_local(struct parsedfile *, int, const char *);
-static int handle_tordns_enabled(struct parsedfile *, int, char *);
-static int handle_tordns_deadpool_range(struct parsedfile *, int, const char *);
-static int handle_tordns_cache_size(struct parsedfile *, char *);
-static int handle_defuser(struct parsedfile *, int, char *);
-static int handle_defpass(struct parsedfile *, int, char *);
-static int make_netent(char *value, struct netent **ent);
-
-int read_config (char *filename, struct parsedfile *config) {
- FILE *conf;
- char line[MAXLINE];
- int rc = 0;
- int lineno = 1;
- struct serverent *server;
-
- /* Clear out the structure */
- memset(config, 0x0, sizeof(*config));
-
- /* Initialization */
- currentcontext = &(config->defaultserver);
-
- /* Tordns defaults */
- config->tordns_cache_size = 256;
- config->tordns_enabled = 1;
-
-
- /* If a filename wasn't provided, use the default */
- if (filename == NULL) {
- strncpy(line, CONF_FILE, sizeof(line) - 1);
- /* Insure null termination */
- line[sizeof(line) - 1] = (char) 0;
- filename = line;
- show_msg(MSGDEBUG, "Configuration file not provided by TORSOCKS_CONF_FILE "
- "environment variable, attempting to use defaults in %s.\n", filename);
- }
-
- /* If there is no configuration file use reasonable defaults for Tor */
- if ((conf = fopen(filename, "r")) == NULL) {
- show_msg(MSGERR, "Could not open socks configuration file "
- "(%s) errno (%d), assuming sensible defaults for Tor.\n", filename, errno);
- memset(&(config->defaultserver), 0x0, sizeof(config->defaultserver));
- check_server(&(config->defaultserver));
- handle_local(config, 0, "127.0.0.0/255.0.0.0");
- handle_local(config, 0, "10.0.0.0/255.0.0.0");
- handle_local(config, 0, "192.168.0.0/255.255.0.0");
- handle_local(config, 0, "172.16.0.0/255.240.0.0");
- handle_local(config, 0, "169.254.0.0/255.255.0.0");
- rc = 1; /* Severe errors reading configuration */
- } else {
- memset(&(config->defaultserver), 0x0, sizeof(config->defaultserver));
-
- while (NULL != fgets(line, MAXLINE, conf)) {
- /* This line _SHOULD_ end in \n so we */
- /* just chop off the \n and hand it on */
- if (strlen(line) > 0)
- line[strlen(line) - 1] = '\0';
- handle_line(config, line, lineno);
- lineno++;
- }
- fclose(conf);
-
- /* Always add the 127.0.0.1/255.0.0.0 subnet to local */
- handle_local(config, 0, "127.0.0.0/255.0.0.0");
- /* We always consider this local, because many users' dsl
- routers act as their DNS. */
- handle_local(config, 0, "10.0.0.0/255.0.0.0");
- handle_local(config, 0, "192.168.0.0/255.255.0.0");
- handle_local(config, 0, "172.16.0.0/255.240.0.0");
- handle_local(config, 0, "169.254.0.0/255.255.0.0");
- handle_local(config, 0, "192.168.0.0/255.255.0.0");
-
- /* Check default server */
- check_server(&(config->defaultserver));
- server = (config->paths);
- while (server != NULL) {
- check_server(server);
- server = server->next;
- }
- }
-
- /* Initialize tordns deadpool_range if not supplied */
- if(config->tordns_deadpool_range == NULL) {
- handle_tordns_deadpool_range(config, 0, "127.0.69.0/255.255.255.0");
- }
-
- return(rc);
-}
-
-/* Check server entries (and establish defaults) */
-static int check_server(struct serverent *server) {
-
- /* Default to the default Tor Socks port */
- if (server->port == 0) {
- server->port = 9050;
- }
-
- /* Default to a presumably local installation of Tor */
- if (server->address == NULL) {
- server->address = strdup("127.0.0.1");
- }
-
- /* Default to SOCKS V4 */
- if (server->type == 0) {
- server->type = 4;
- }
-
- return(0);
-}
-
-
-
-static int handle_line(struct parsedfile *config, char *line, int lineno) {
- char *words[10];
- static char savedline[MAXLINE];
- int nowords = 0, i;
-
- /* Save the input string */
- strncpy(savedline, line, MAXLINE - 1);
- savedline[MAXLINE - 1] = (char) 0;
- /* Tokenize the input string */
- nowords = tokenize(line, 10, words);
-
- /* Set the spare slots to an empty string to simplify */
- /* processing */
- for (i = nowords; i < 10; i++)
- words[i] = NULL;
-
- if (nowords > 0) {
- /* Now this can either be a "path" block starter or */
- /* ender, otherwise it has to be a pair (<name> = */
- /* <value>) */
- if (!strcmp(words[0], "path")) {
- handle_path(config, lineno, nowords, words);
- } else if (!strcmp(words[0], "}")) {
- handle_endpath(config, lineno, nowords);
- } else {
- /* Has to be a pair */
- if ((nowords != 3) || (strcmp(words[1], "="))) {
- show_msg(MSGERR, "Malformed configuration pair "
- "on line %d in configuration "
- "file, \"%s\"\n", lineno, savedline);
- } else if (!strcmp(words[0], "reaches")) {
- handle_reaches(lineno, words[2]);
- } else if (!strcmp(words[0], "server")) {
- handle_server(config, lineno, words[2]);
- } else if (!strcmp(words[0], "server_port")) {
- handle_port(config, lineno, words[2]);
- } else if (!strcmp(words[0], "server_type")) {
- handle_type(config, lineno, words[2]);
- } else if (!strcmp(words[0], "default_user")) {
- handle_defuser(config, lineno, words[2]);
- } else if (!strcmp(words[0], "default_pass")) {
- handle_defpass(config, lineno, words[2]);
- } else if (!strcmp(words[0], "local")) {
- handle_local(config, lineno, words[2]);
- } else if (!strcmp(words[0], "tordns_enable")) {
- handle_tordns_enabled(config, lineno, words[2]);
- } else if (!strcmp(words[0], "tordns_deadpool_range")) {
- handle_tordns_deadpool_range(config, lineno, words[2]);
- } else if (!strcmp(words[0], "tordns_cache_size")) {
- handle_tordns_cache_size(config, words[2]);
- } else {
- show_msg(MSGERR, "Invalid pair type (%s) specified "
- "on line %d in configuration file, "
- "\"%s\"\n", words[0], lineno,
- savedline);
- }
- }
- }
-
- return(0);
-}
-
-/* This routines breaks up input lines into tokens */
-/* and places these tokens into the array specified */
-/* by tokens */
-static int tokenize(char *line, int arrsize, char *tokens[]) {
- int tokenno = -1;
- int finished = 0;
-
- /* Whitespace is ignored before and after tokens */
- while ((tokenno < (arrsize - 1)) &&
- (line = line + strspn(line, " \t")) &&
- (*line != (char) 0) &&
- (!finished)) {
- tokenno++;
- tokens[tokenno] = line;
- line = line + strcspn(line, " \t");
- *line = (char) 0;
- line++;
-
- /* We ignore everything after a # */
- if (*tokens[tokenno] == '#') {
- finished = 1;
- tokenno--;
- }
- }
-
- return(tokenno + 1);
-}
-
-static int handle_path(struct parsedfile *config, int lineno, int nowords, char *words[]) {
- struct serverent *newserver;
-
- if ((nowords != 2) || (strcmp(words[1], "{"))) {
- show_msg(MSGERR, "Badly formed path open statement on line %d "
- "in configuration file (should look like "
- "\"path {\")\n", lineno);
- } else if (currentcontext != &(config->defaultserver)) {
- /* You cannot nest path statements so check that */
- /* the current context is defaultserver */
- show_msg(MSGERR, "Path statements cannot be nested on line %d "
- "in configuration file\n", lineno);
- } else {
- /* Open up a new serverent, put it on the list */
- /* then set the current context */
- if ((newserver = malloc(sizeof(*newserver))) == NULL)
- exit(-1);
-
- /* Initialize the structure */
- show_msg(MSGDEBUG, "New server structure from line %d in configuration file going "
- "to 0x%08x\n", lineno, newserver);
- memset(newserver, 0x0, sizeof(*newserver));
- newserver->next = config->paths;
- newserver->lineno = lineno;
- config->paths = newserver;
- currentcontext = newserver;
- }
-
- return(0);
-}
-
-static int handle_endpath(struct parsedfile *config, int lineno, int nowords) {
-
- if (nowords != 1) {
- show_msg(MSGERR, "Badly formed path close statement on line "
- "%d in configuration file (should look like "
- "\"}\")\n", lineno);
- } else {
- currentcontext = &(config->defaultserver);
- }
-
- /* We could perform some checking on the validty of data in */
- /* the completed path here, but thats what verifyconf is */
- /* designed to do, no point in weighing down libtorsocks */
-
- return(0);
-}
-
-static int handle_reaches(int lineno, char *value) {
- int rc;
- struct netent *ent;
-
- rc = make_netent(value, &ent);
- switch(rc) {
- case 1:
- show_msg(MSGERR, "Local network specification (%s) is not validly "
- "constructed in reach statement on line "
- "%d in configuration "
- "file\n", value, lineno);
- return(0);
- break;
- case 2:
- show_msg(MSGERR, "IP in reach statement "
- "network specification (%s) is not valid on line "
- "%d in configuration file\n", value, lineno);
- return(0);
- break;
- case 3:
- show_msg(MSGERR, "SUBNET in reach statement "
- "network specification (%s) is not valid on "
- "line %d in configuration file\n", value,
- lineno);
- return(0);
- break;
- case 4:
- show_msg(MSGERR, "IP (%s) & ", inet_ntoa(ent->localip));
- show_msg(MSGERR, "SUBNET (%s) != IP on line %d in "
- "configuration file, ignored\n",
- inet_ntoa(ent->localnet), lineno);
- return(0);
- break;
- case 5:
- show_msg(MSGERR, "Start port in reach statement "
- "network specification (%s) is not valid on line "
- "%d in configuration file\n", value, lineno);
- return(0);
- break;
- case 6:
- show_msg(MSGERR, "End port in reach statement "
- "network specification (%s) is not valid on line "
- "%d in configuration file\n", value, lineno);
- return(0);
- break;
- case 7:
- show_msg(MSGERR, "End port in reach statement "
- "network specification (%s) is less than the start "
- "port on line %d in configuration file\n", value,
- lineno);
- return(0);
- break;
- }
-
- /* The entry is valid so add it to linked list */
- ent -> next = currentcontext -> reachnets;
- currentcontext -> reachnets = ent;
-
- return(0);
-}
-
-static int handle_server(struct parsedfile *config, int lineno, char *value) {
- char *ip;
-
- ip = strsplit(NULL, &value, " ");
-
- /* We don't verify this ip/hostname at this stage, */
- /* its resolved immediately before use in torsocks.c */
- if (currentcontext->address == NULL)
- currentcontext->address = strdup(ip);
- else {
- if (currentcontext == &(config->defaultserver))
- show_msg(MSGERR, "Only one default SOCKS server "
- "may be specified at line %d in "
- "configuration file\n", lineno);
- else
- show_msg(MSGERR, "Only one SOCKS server may be specified "
- "per path on line %d in configuration "
- "file. (Path begins on line %d)\n",
- lineno, currentcontext->lineno);
- }
-
- return(0);
-}
-
-static int handle_port(struct parsedfile *config, int lineno, char *value) {
-
- if (currentcontext->port != 0) {
- if (currentcontext == &(config->defaultserver))
- show_msg(MSGERR, "Server port may only be specified "
- "once for default server, at line %d "
- "in configuration file\n", lineno);
- else
- show_msg(MSGERR, "Server port may only be specified "
- "once per path on line %d in configuration "
- "file. (Path begins on line %d)\n",
- lineno, currentcontext->lineno);
- } else {
- errno = 0;
- currentcontext->port = (unsigned short int)
- (strtol(value, (char **)NULL, 10));
- if ((errno != 0) || (currentcontext->port == 0)) {
- show_msg(MSGERR, "Invalid server port number "
- "specified in configuration file "
- "(%s) on line %d\n", value, lineno);
- currentcontext->port = 0;
- }
- }
-
- return(0);
-}
-
-static int handle_defuser(struct parsedfile *config, int lineno, char *value) {
-
- if (currentcontext->defuser != NULL) {
- if (currentcontext == &(config->defaultserver))
- show_msg(MSGERR, "Default username may only be specified "
- "once for default server, at line %d "
- "in configuration file\n", lineno);
- else
- show_msg(MSGERR, "Default username may only be specified "
- "once per path on line %d in configuration "
- "file. (Path begins on line %d)\n",
- lineno, currentcontext->lineno);
- } else {
- currentcontext->defuser = strdup(value);
- }
-
- return(0);
-}
-
-static int handle_defpass(struct parsedfile *config, int lineno, char *value) {
-
- if (currentcontext->defpass != NULL) {
- if (currentcontext == &(config->defaultserver))
- show_msg(MSGERR, "Default password may only be specified "
- "once for default server, at line %d "
- "in configuration file\n", lineno);
- else
- show_msg(MSGERR, "Default password may only be specified "
- "once per path on line %d in configuration "
- "file. (Path begins on line %d)\n",
- lineno, currentcontext->lineno);
- } else {
- currentcontext->defpass = strdup(value);
- }
-
- return(0);
-}
-
-static int handle_type(struct parsedfile *config, int lineno, char *value) {
-
- if (currentcontext->type != 0) {
- if (currentcontext == &(config->defaultserver))
- show_msg(MSGERR, "Server type may only be specified "
- "once for default server, at line %d "
- "in configuration file\n", lineno);
- else
- show_msg(MSGERR, "Server type may only be specified "
- "once per path on line %d in configuration "
- "file. (Path begins on line %d)\n",
- lineno, currentcontext->lineno);
- } else {
- errno = 0;
- currentcontext->type = (int) strtol(value, (char **)NULL, 10);
- if ((errno != 0) || (currentcontext->type == 0) ||
- ((currentcontext->type != 4) && (currentcontext->type != 5))) {
- show_msg(MSGERR, "Invalid server type (%s) "
- "specified in configuration file "
- "on line %d, only 4 or 5 may be "
- "specified\n", value, lineno);
- currentcontext->type = 0;
- }
- }
-
- return(0);
-}
-
-static int handle_flag(char *value)
-{
- if(!strcasecmp(value, "true") || !strcasecmp(value, "yes")
- || !strcmp(value, "1")) {
- return 1;
- } else if (!strcasecmp(value, "false") || !strcasecmp(value, "no")
- || !strcmp(value, "0")) {
- return 0;
- } else {
- return -1;
- }
-}
-
-static int handle_tordns_enabled(struct parsedfile *config, int lineno,
- char *value)
-{
- int val = handle_flag(value);
- if(val == -1) {
- show_msg(MSGERR, "Invalid value %s supplied for tordns_enabled at "
- "line %d in config file, IGNORED\n", value, lineno);
- } else {
- config->tordns_enabled = val;
- }
- return 0;
-}
-
-static int handle_tordns_cache_size(struct parsedfile *config,
- char *value)
-{
- char *endptr;
- long size = strtol(value, &endptr, 10);
- if(*endptr != '\0') {
- show_msg(MSGERR, "Error parsing integer value for "
- "tordns_cache_size (%s), using default %d\n",
- value, config->tordns_cache_size);
- } else if(size < 128) {
- show_msg(MSGERR, "The value supplied for tordns_cache_size (%d) "
- "is too small (<128), using default %d\n", size,
- config->tordns_cache_size);
- } else if(size > 4096) {
- show_msg(MSGERR, "The value supplied for tordns_cache_range (%d) "
- "is too large (>4096), using default %d\n", size,
- config->tordns_cache_size);
- } else {
- config->tordns_cache_size = size;
- }
- return 0;
-}
-
-static int handle_tordns_deadpool_range(struct parsedfile *config, int lineno,
- const char *value)
-{
- int rc;
- struct netent *ent;
-
- if (config->tordns_deadpool_range != NULL) {
- show_msg(MSGERR, "Only one 'deadpool' entry permitted, found a "
- "second at line %d in configuration file.\n");
- return(0);
- }
-
- if (currentcontext != &(config->defaultserver)) {
- show_msg(MSGERR, "Deadpool cannot be specified in path "
- "block at line %d in configuration file. "
- "(Path block started at line %d)\n",
- lineno, currentcontext->lineno);
- return(0);
- }
-
- rc = make_netent((char *)value, &ent);
- /* This is copied from handle_local and should probably be folded into
- a generic whinge() function or something */
- switch(rc) {
- case 1:
- show_msg(MSGERR, "The deadpool specification (%s) is not validly "
- "constructed on line %d in configuration "
- "file\n", value, lineno);
- return(0);
- break;
- case 2:
- show_msg(MSGERR, "IP for deadpool "
- "network specification (%s) is not valid on line "
- "%d in configuration file\n", value, lineno);
- return(0);
- break;
- case 3:
- show_msg(MSGERR, "SUBNET for "
- "deadpool network specification (%s) is not valid on "
- "line %d in configuration file\n", value,
- lineno);
- return(0);
- break;
- case 4:
- show_msg(MSGERR, "IP (%s) & ", inet_ntoa(ent->localip));
- show_msg(MSGERR, "SUBNET (%s) != IP on line %d in "
- "configuration file, ignored\n",
- inet_ntoa(ent->localnet), lineno);
- return(0);
- case 5:
- case 6:
- case 7:
- show_msg(MSGERR, "Port specification is invalid and "
- "not allowed in deadpool specification "
- "(%s) on line %d in configuration file\n",
- value, lineno);
- return(0);
- break;
- }
- if (ent->startport || ent->endport) {
- show_msg(MSGERR, "Port specification is "
- "not allowed in deadpool specification "
- "(%s) on line %d in configuration file\n",
- value, lineno);
- return(0);
- }
-
- config->tordns_deadpool_range = ent;
- return 0;
-}
-
-static int handle_local(struct parsedfile *config, int lineno, const char *value) {
- int rc;
- struct netent *ent;
-
- if (currentcontext != &(config->defaultserver)) {
- show_msg(MSGERR, "Local networks cannot be specified in path "
- "block at line %d in configuration file. "
- "(Path block started at line %d)\n",
- lineno, currentcontext->lineno);
- return(0);
- }
-
- rc = make_netent((char *)value, &ent);
- switch(rc) {
- case 1:
- show_msg(MSGERR, "Local network specification (%s) is not validly "
- "constructed on line %d in configuration "
- "file\n", value, lineno);
- return(0);
- break;
- case 2:
- show_msg(MSGERR, "IP for local "
- "network specification (%s) is not valid on line "
- "%d in configuration file\n", value, lineno);
- return(0);
- break;
- case 3:
- show_msg(MSGERR, "SUBNET for "
- "local network specification (%s) is not valid on "
- "line %d in configuration file\n", value,
- lineno);
- return(0);
- break;
- case 4:
- show_msg(MSGERR, "IP (%s) & ", inet_ntoa(ent->localip));
- show_msg(MSGERR, "SUBNET (%s) != IP on line %d in "
- "configuration file, ignored\n",
- inet_ntoa(ent->localnet), lineno);
- return(0);
- case 5:
- case 6:
- case 7:
- show_msg(MSGERR, "Port specification is invalid and "
- "not allowed in local network specification "
- "(%s) on line %d in configuration file\n",
- value, lineno);
- return(0);
- break;
- }
-
- if (ent->startport || ent->endport) {
- show_msg(MSGERR, "Port specification is "
- "not allowed in local network specification "
- "(%s) on line %d in configuration file\n",
- value, lineno);
- return(0);
- }
-
- /* The entry is valid so add it to linked list */
- ent -> next = config->localnets;
- (config->localnets) = ent;
-
- return(0);
-}
-
-/* Construct a netent given a string like */
-/* "198.126.0.1[:portno[-portno]]/255.255.255.0" */
-int make_netent(char *value, struct netent **ent) {
- char *ip;
- char *subnet;
- char *startport = NULL;
- char *endport = NULL;
- char *badchar;
- char separator;
- static char buf[200];
- char *split;
-
- /* Get a copy of the string so we can modify it */
- strncpy(buf, value, sizeof(buf) - 1);
- buf[sizeof(buf) - 1] = (char) 0;
- split = buf;
-
- /* Now rip it up */
- ip = strsplit(&separator, &split, "/:");
- if (separator == ':') {
- /* We have a start port */
- startport = strsplit(&separator, &split, "-/");
- if (separator == '-')
- /* We have an end port */
- endport = strsplit(&separator, &split, "/");
- }
- subnet = strsplit(NULL, &split, " \n");
-
- if ((ip == NULL) || (subnet == NULL)) {
- /* Network specification not validly constructed */
- return(1);
- }
-
- /* Allocate the new entry */
- if ((*ent = (struct netent *) malloc(sizeof(struct netent)))
- == NULL) {
- /* If we couldn't malloc some storage, leave */
- exit(1);
- }
-
- show_msg(MSGDEBUG, "New network entry for %s going to 0x%08x\n", ip, *ent);
-
- if (!startport)
- (*ent)->startport = 0;
- if (!endport)
- (*ent)->endport = 0;
-
-#ifdef HAVE_INET_ADDR
- if (((*ent)->localip.s_addr = inet_addr(ip)) == -1) {
-#elif defined(HAVE_INET_ATON)
- if (!(inet_aton(ip, &((*ent)->localip)))) {
-#endif
- /* Badly constructed IP */
- free(*ent);
- return(2);
- }
-#ifdef HAVE_INET_ADDR
- else if (((*ent)->localnet.s_addr = inet_addr(subnet)) == -1) {
-#elif defined(HAVE_INET_ATON)
- else if (!(inet_aton(subnet, &((*ent)->localnet)))) {
-#endif
- /* Badly constructed subnet */
- free(*ent);
- return(3);
- } else if (((*ent)->localip.s_addr &
- (*ent)->localnet.s_addr) !=
- (*ent)->localip.s_addr) {
- /* Subnet and Ip != Ip */
- free(*ent);
- return(4);
- } else if (startport &&
- (!((*ent)->startport = strtol(startport, &badchar, 10)) ||
- (*badchar != 0) || ((*ent)->startport > 65535))) {
- /* Bad start port */
- free(*ent);
- return(5);
- } else if (endport &&
- (!((*ent)->endport = strtol(endport, &badchar, 10)) ||
- (*badchar != 0) || ((*ent)->endport > 65535))) {
- /* Bad end port */
- free(*ent);
- return(6);
- } else if (((*ent)->startport > (*ent)->endport) && !(startport && !endport)) {
- /* End port is less than start port */
- free(*ent);
- return(7);
- }
-
- if (startport && !endport)
- (*ent)->endport = (*ent)->startport;
-
- return(0);
-}
-
-int is_local(struct parsedfile *config, struct in_addr *testip) {
- struct netent *ent;
- char buf[16];
- inet_ntop(AF_INET, testip, buf, sizeof(buf));
- show_msg(MSGDEBUG, "checking if address: %s is local"
- "\n",
- buf);
-
- for (ent = (config->localnets); ent != NULL; ent = ent -> next) {
- inet_ntop(AF_INET, &ent->localnet, buf, sizeof(buf));
- show_msg(MSGDEBUG, "localnet addr: %s"
- "\n",
- buf);
- inet_ntop(AF_INET, &ent->localip, buf, sizeof(buf));
- show_msg(MSGDEBUG, "localip addr: %s"
- "\n",
- buf);
- show_msg(MSGDEBUG, "result testip->s_addr & ent->localnet.s_addr : %i"
- "\n",
- testip->s_addr & ent->localnet.s_addr);
- show_msg(MSGDEBUG, "result ent->localip.s_addr & ent->localnet.s_addr : %i"
- "\n",
- ent->localip.s_addr & ent->localnet.s_addr);
- show_msg(MSGDEBUG, "result ent->localip.s_addr : %i"
- "\n",
- ent->localip.s_addr);
- if ((testip->s_addr & ent->localnet.s_addr) ==
- (ent->localip.s_addr & ent->localnet.s_addr)) {
- show_msg(MSGDEBUG, "address: %s is local"
- "\n",
- buf);
- return(0);
- }
- }
-
- inet_ntop(AF_INET, testip, buf, sizeof(buf));
- show_msg(MSGDEBUG, "address: %s is not local"
- "\n",
- buf);
- return(1);
-}
-
-/* Find the appropriate server to reach an ip */
-int pick_server(struct parsedfile *config, struct serverent **ent,
- struct in_addr *ip, unsigned int port) {
- struct netent *net;
- char ipbuf[64];
-
- show_msg(MSGDEBUG, "Picking appropriate server for %s\n", inet_ntoa(*ip));
- *ent = (config->paths);
- while (*ent != NULL) {
- /* Go through all the servers looking for one */
- /* with a path to this network */
- show_msg(MSGDEBUG, "Checking SOCKS server %s\n",
- ((*ent)->address ? (*ent)->address : "(No Address)"));
- net = (*ent)->reachnets;
- while (net != NULL) {
- strcpy(ipbuf, inet_ntoa(net->localip));
- show_msg(MSGDEBUG, "Server can reach %s/%s\n",
- ipbuf, inet_ntoa(net->localnet));
- if (((ip->s_addr & net->localnet.s_addr) ==
- (net->localip.s_addr & net->localnet.s_addr)) &&
- (!net->startport ||
- ((net->startport <= port) && (net->endport >= port))))
- {
- show_msg(MSGDEBUG, "This server can reach target\n");
- /* Found the net, return */
- return(0);
- }
- net = net->next;
- }
- (*ent) = (*ent)->next;
- }
-
- *ent = &(config->defaultserver);
-
- return(0);
-}
-
-/* This function is very much like strsep, it looks in a string for */
-/* a character from a list of characters, when it finds one it */
-/* replaces it with a \0 and returns the start of the string */
-/* (basically spitting out tokens with arbitrary separators). If no */
-/* match is found the remainder of the string is returned and */
-/* the start pointer is set to be NULL. The difference between */
-/* standard strsep and this function is that this one will */
-/* set *separator to the character separator found if it isn't null */
-char *strsplit(char *separator, char **text, const char *search) {
- unsigned int len;
- char *ret;
-
- ret = *text;
-
- if (*text == NULL) {
- if (separator)
- *separator = '\0';
- return(NULL);
- } else {
- len = strcspn(*text, search);
- if (len == strlen(*text)) {
- if (separator)
- *separator = '\0';
- *text = NULL;
- } else {
- *text = *text + len;
- if (separator)
- *separator = **text;
- **text = '\0';
- *text = *text + 1;
- }
- }
-
- return(ret);
-}
diff --git a/src/parser.h b/src/parser.h
deleted file mode 100644
index 91e6d04..0000000
--- a/src/parser.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/***************************************************************************
- * *
- * Copyright (C) 2000-2008 Shaun Clowes <delius@xxxxxxxxxxx> *
- * Copyright (C) 2008-2011 Robert Hogan <robert@xxxxxxxxxxxxxxx> *
- * *
- * 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. *
- ***************************************************************************/
-
-/* parser.h - Structures, functions and global variables for the
- torsocks parsing routines */
-
-#ifndef _PARSER_H
-
-#define _PARSER_H 1
-
-/* Structure definitions */
-
-/* Structure representing one server specified in the config */
-struct serverent {
- int lineno; /* Line number in conf file this path started on */
- char *address; /* Address/hostname of server */
- int port; /* Port number of server */
- int type; /* Type of server (4/5) */
- char *defuser; /* Default username for this socks server */
- char *defpass; /* Default password for this socks server */
- struct netent *reachnets; /* Linked list of nets from this server */
- struct serverent *next; /* Pointer to next server entry */
-};
-
-/* Structure representing a network */
-struct netent {
- struct in_addr localip; /* Base IP of the network */
- struct in_addr localnet; /* Mask for the network */
- unsigned long startport; /* Range of ports for the */
- unsigned long endport; /* network */
- struct netent *next; /* Pointer to next network entry */
-};
-
-/* Structure representing a complete parsed file */
-struct parsedfile {
- struct netent *localnets;
- struct serverent defaultserver;
- struct serverent *paths;
- int tordns_enabled;
- int tordns_failopen;
- unsigned int tordns_cache_size;
- struct netent *tordns_deadpool_range;
-};
-
-/* Functions provided by parser module */
-int read_config(char *, struct parsedfile *);
-int is_local(struct parsedfile *, struct in_addr *);
-int pick_server(struct parsedfile *, struct serverent **, struct in_addr *, unsigned int port);
-char *strsplit(char *separator, char **text, const char *search);
-
-#endif
diff --git a/src/socks.c b/src/socks.c
deleted file mode 100644
index 8497728..0000000
--- a/src/socks.c
+++ /dev/null
@@ -1,633 +0,0 @@
-/***************************************************************************
- * *
- * Copyright (C) 2000-2008 Shaun Clowes <delius@xxxxxxxxxxx> *
- * Copyright (C) 2008-2011 Robert Hogan <robert@xxxxxxxxxxxxxxx> *
- * *
- * 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 <pthread.h>
-#include <stdarg.h>
-#if !defined(__APPLE__) && !defined(__darwin__)
-#include <sys/socket.h>
-#endif
-#include <resolv.h>
-
-#include "common.h"
-#include "dead_pool.h"
-#include "parser.h"
-#include "socks.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);
-
-
-dead_pool *pool = NULL;
-struct connreq *requests = NULL;
-
-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
deleted file mode 100644
index 6dd497f..0000000
--- a/src/socks.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/***************************************************************************
- * *
- * Copyright (C) 2000-2008 Shaun Clowes <delius@xxxxxxxxxxx> *
- * Copyright (C) 2008-2011 Robert Hogan <robert@xxxxxxxxxxxxxxx> *
- * *
- * 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 */
-extern dead_pool *pool;
-extern struct connreq *requests;
-
-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
deleted file mode 100644
index 597c107..0000000
--- a/src/torsocks.c
+++ /dev/null
@@ -1,1108 +0,0 @@
-/***************************************************************************
- * *
- * *
- * Copyright (C) 2000-2008 Shaun Clowes <delius@xxxxxxxxxxx> *
- * Copyright (C) 2008-2011 Robert Hogan <robert@xxxxxxxxxxxxxxx> *
- * *
- * 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
-
-/* Global configuration variables */
-const char *torsocks_progname = "libtorsocks"; /* Name used in err msgs */
-
-/* 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 <pthread.h>
-#include <stdarg.h>
-#if !defined(__APPLE__) && !defined(__darwin__)
-#include <sys/socket.h>
-#endif
-#include <resolv.h>
-
-#include "common.h"
-#include "dead_pool.h"
-#include "parser.h"
-#include "socks.h"
-
-/* Some function names are macroized on Darwin. Allow those names
- to expand accordingly. */
-#define EXPAND_GUTS(x) torsocks_##x##_guts
-#define EXPAND_GUTS_NAME(x) EXPAND_GUTS(x)
-
-/* Function prototypes for original functions that we patch */
-#ifdef SUPPORT_RES_API
-int (*realres_init)(void);
-#endif
-#define PATCH_TABLE_EXPANSION(e,r,s,n,b,m) r (*real##n)(s##SIGNATURE);
-#include "expansion_table.h"
-#undef PATCH_TABLE_EXPANSION
-#undef DARWIN_EXPANSION
-
-static struct parsedfile config;
-static int suid = 0;
-static char *conffile = NULL;
-
-/* Exported Function Prototypes */
-void __attribute__ ((constructor)) torsocks_init(void);
-
-/* Function prototypes for our patches */
-#ifdef SUPPORT_RES_API
-int res_init(void);
-#endif
-
-#define PATCH_TABLE_EXPANSION(e,r,s,n,b,m) r n(s##SIGNATURE);
-#define DARWIN_EXPANSION(e,r,s,n,b,m) r n(s##SIGNATURE) __asm("_" m);
-#include "expansion_table.h"
-#undef PATCH_TABLE_EXPANSION
-#undef DARWIN_EXPANSION
-
-/* Private Function Prototypes */
-/* no torsocks_res_init_guts */
-#define PATCH_TABLE_EXPANSION(e,r,s,n,b,m) r torsocks_##b##_guts(s##SIGNATURE, r (*original_##b)(s##SIGNATURE));
-#include "expansion_table.h"
-#undef PATCH_TABLE_EXPANSION
-
-static int get_config();
-static int get_environment();
-static int deadpool_init(void);
-
-static pthread_mutex_t torsocks_init_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-void torsocks_init(void)
-{
- pthread_mutex_lock(&torsocks_init_mutex);
-
- show_msg(MSGDEBUG, "In torsocks_init \n");
-
- get_environment();
- get_config();
-
-#ifdef USE_OLD_DLSYM
- void *lib;
-#endif
-
- /* We could do all our initialization here, but to be honest */
- /* most programs that are run won't use our services, so */
- /* we do our general initialization on first call */
-
- /* Determine the logging level */
- suid = (getuid() != geteuid());
-
- dlerror();
-#ifndef USE_OLD_DLSYM
- #ifdef SUPPORT_RES_API
- torsocks_find_library("res_init", MSGERR, realres_init);
- #endif
- #define PATCH_TABLE_EXPANSION(e,r,s,n,b,m) torsocks_find_library(m, MSG##e, real##n);
- #include "expansion_table.h"
- #undef PATCH_TABLE_EXPANSION
-#else
- lib = dlopen(LIBCONNECT, RTLD_LAZY);
- realconnect = dlsym(lib, "connect");
- realselect = dlsym(lib, "select");
- realpoll = dlsym(lib, "poll");
- realgethostbyname = dlsym(lib, "gethostbyname");
- realgethostbyaddr = dlsym(lib, "gethostbyaddr");
- realgetaddrinfo = dlsym(lib, "getaddrinfo");
- realgetipnodebyname = dlsym(lib, "getipnodebyname");
- realsendto = dlsym(lib, "sendto");
- realsendmsg = dlsym(lib, "sendmsg");
- dlclose(lib);
- lib = dlopen(LIBC, RTLD_LAZY);
- realclose = dlsym(lib, "close");
- dlclose(lib);
- #ifdef SUPPORT_RES_API
- lib = dlopen(LIBRESOLV, RTLD_LAZY);
- realres_init = dlsym(lib, "res_init");
- realresquery = dlsym(lib, "res_query");
- realressend = dlsym(lib, "res_send");
- realresquerydomain = dlsym(lib, "res_querydomain");
- realressearch = dlsym(lib, "res_search");
- dlclose(lib);
- #endif
-#endif
- /* Unfortunately, we can't do this lazily because otherwise our mmap'd
- area won't be shared across fork()s. */
- if (!deadpool_init()) {
- show_msg(MSGERR, "Fatal error: exiting\n");
- exit(1);
- }
-
- pthread_mutex_unlock(&torsocks_init_mutex);
-
- show_msg(MSGDEBUG, "Exit torsocks_init \n");
-}
-
-static int get_environment()
-{
- static int done = 0;
- int loglevel = MSGERR;
- char *logfile = NULL;
- char *env;
-
- if (done)
- return(0);
-
- /* Determine the logging level */
- if ((env = getenv("TORSOCKS_DEBUG")))
- loglevel = atoi(env);
- if (((env = getenv("TORSOCKS_DEBUG_FILE"))) && !suid)
- logfile = env;
- set_log_options(loglevel, logfile, (loglevel == MSGTEST) ? 0 : 1);
-
- done = 1;
-
- return(0);
-}
-
-static int get_config ()
-{
- static int done = 0;
-
- if (done)
- return(0);
-
- /* Determine the location of the config file */
-#ifdef ALLOW_ENV_CONFIG
- if (!suid)
- conffile = getenv("TORSOCKS_CONF_FILE");
-#endif
-
- /* Read in the config file */
- read_config(conffile, &config);
- if (config.paths)
- show_msg(MSGDEBUG, "First lineno for first path is %d\n", config.paths->lineno);
-
- done = 1;
-
- return(0);
-}
-
-/* Patch trampoline functions */
-/* no torsocks_res_init_guts */
-#define PATCH_TABLE_EXPANSION(e,r,s,n,b,m) \
- r n(s##SIGNATURE) { \
- if (!real##n) { \
- torsocks_find_library(m, MSG##e, real##n);\
- } \
- return torsocks_##b##_guts(s##ARGNAMES, real##n); \
- }
-#include "expansion_table.h"
-#undef PATCH_TABLE_EXPANSION
-
-int torsocks_connect_guts(CONNECT_SIGNATURE, int (*original_connect)(CONNECT_SIGNATURE))
-{
- struct sockaddr_in *connaddr;
- struct sockaddr_in peer_address;
- struct sockaddr_in server_address;
- int gotvalidserver = 0, rc;
- socklen_t namelen = sizeof(peer_address);
- int sock_type = -1;
- socklen_t sock_type_len = sizeof(sock_type);
- int res = -1;
- struct serverent *path;
- struct connreq *newconn;
-
- /* If the real connect doesn't exist, we're stuffed */
- if (original_connect == NULL) {
- show_msg(MSGERR, "Unresolved symbol: connect\n");
- return(-1);
- }
-
- show_msg(MSGTEST, "Got connection request\n");
-
- connaddr = (struct sockaddr_in *) __addr;
-
- /* Get the type of the socket */
- getsockopt(__fd, SOL_SOCKET, SO_TYPE,
- (void *) &sock_type, &sock_type_len);
-
- show_msg(MSGDEBUG, "sin_family: %i\n", connaddr->sin_family);
-
- show_msg(MSGDEBUG, "sockopt: %i \n", sock_type);
-
- /* If the address is local refuse it. We do this because it could
- be a TCP DNS request to a local DNS server.*/
- if (!(is_local(&config, &(connaddr->sin_addr))) &&
- !is_dead_address(pool, connaddr->sin_addr.s_addr)) {
- char buf[16];
- inet_ntop(AF_INET, &(connaddr->sin_addr), buf, sizeof(buf));
- show_msg(MSGERR, "connect: Connection is to a local address (%s), may be a "
- "TCP DNS request to a local DNS server so have to reject to be safe. "
- "Please report a bug to http://code.google.com/p/torsocks/issues/entry if "
- "this is preventing a program from working properly with torsocks.\n", buf);
- return -1;
- }
-
- /* If this is an INET6, we'll refuse it. */
- if ((connaddr->sin_family == AF_INET6)) {
- show_msg(MSGERR, "connect: Connection is IPv6: rejecting.\n");
- errno = EAFNOSUPPORT;
- return -1;
- }
-
- /* If this isn't an INET socket we can't */
- /* handle it, just call the real connect now */
- if ((connaddr->sin_family != AF_INET)) {
- show_msg(MSGDEBUG, "connect: Connection isn't IPv4, ignoring\n");
- return(original_connect(__fd, __addr, __len));
- }
-
- /* If this a UDP socket */
- /* then we refuse it, since it is probably a DNS request */
- if ((sock_type != SOCK_STREAM)) {
- show_msg(MSGERR, "connect: Connection is a UDP or ICMP stream, may be a "
- "DNS request or other form of leak: rejecting.\n");
- return -1;
- }
-
- /* If we haven't initialized yet, do it now */
- get_config();
-
- /* Are we already handling this connect? */
- if ((newconn = find_socks_request(__fd, 1))) {
- if (memcmp(&newconn->connaddr, connaddr, sizeof(*connaddr))) {
- /* Ok, they're calling connect on a socket that is in our
- * queue but this connect() isn't to the same destination,
- * they're obviously not trying to check the status of
- * they're non blocking connect, they must have close()d
- * the other socket and created a new one which happens
- * to have the same fd as a request we haven't had the chance
- * to delete yet, so we delete it here. */
- show_msg(MSGDEBUG, "Call to connect received on old "
- "torsocks request for socket %d but to "
- "new destination, deleting old request\n",
- newconn->sockid);
- kill_socks_request(newconn);
- } else {
- /* Ok, this call to connect() is to check the status of
- * a current non blocking connect(). */
- if (newconn->state == FAILED) {
- show_msg(MSGDEBUG, "Call to connect received on failed "
- "request %d, returning %d\n",
- newconn->sockid, newconn->err);
- errno = newconn->err;
- rc = -1;
- } else if (newconn->state == DONE) {
- show_msg(MSGERR, "Call to connect received on completed "
- "request %d\n",
- newconn->sockid, newconn->err);
- rc = 0;
- } else {
- show_msg(MSGDEBUG, "Call to connect received on current request %d\n",
- newconn->sockid);
- rc = handle_request(newconn);
- errno = rc;
- }
- if ((newconn->state == FAILED) || (newconn->state == DONE))
- kill_socks_request(newconn);
- return((rc ? -1 : 0));
- }
- }
-
- /* If the socket is already connected, just call connect */
- /* and get its standard reply */
- if (!getpeername(__fd, (struct sockaddr *) &peer_address, &namelen)) {
- show_msg(MSGDEBUG, "Socket is already connected, defering to "
- "real connect\n");
- return(original_connect(__fd, __addr, __len));
- }
-
- show_msg(MSGDEBUG, "Got connection request for socket %d to "
- "%s\n", __fd, inet_ntoa(connaddr->sin_addr));
-
- /* Ok, so its not local, we need a path to the net */
- pick_server(&config, &path, &(connaddr->sin_addr), ntohs(connaddr->sin_port));
-
- show_msg(MSGDEBUG, "Picked server %s for connection\n",
- (path->address ? path->address : "(Not Provided)"));
- if (path->address == NULL) {
- if (path == &(config.defaultserver))
- show_msg(MSGERR, "Connection needs to be made "
- "via default server but "
- "the default server has not "
- "been specified\n");
- else
- show_msg(MSGERR, "Connection needs to be made "
- "via path specified at line "
- "%d in configuration file but "
- "the server has not been "
- "specified for this path\n",
- path->lineno);
- } else if ((res = resolve_ip(path->address, 0, 0)) == -1) {
- show_msg(MSGERR, "The SOCKS server (%s) listed in the configuration "
- "file which needs to be used for this connection "
- "is invalid\n", path->address);
- } else {
- /* Construct the addr for the socks server */
- server_address.sin_family = AF_INET; /* host byte order */
- server_address.sin_addr.s_addr = res;
- server_address.sin_port = htons(path->port);
- bzero(&(server_address.sin_zero), 8);
-
- /* Complain if this server isn't on a localnet */
- if (is_local(&config, &server_address.sin_addr)) {
- show_msg(MSGERR, "SOCKS server %s (%s) is not on a local subnet!\n",
- path->address, inet_ntoa(server_address.sin_addr));
- } else
- gotvalidserver = 1;
- }
-
- /* If we haven't found a valid server we return connection refused */
- if (!gotvalidserver ||
- !(newconn = new_socks_request(__fd, connaddr, &server_address, path))) {
- errno = ECONNREFUSED;
- return(-1);
- } else {
- /* Now we call the main function to handle the connect. */
- rc = handle_request(newconn);
- /* If the request completed immediately it mustn't have been
- * a non blocking socket, in this case we don't need to know
- * about this socket anymore. */
- if ((newconn->state == FAILED) || (newconn->state == DONE))
- kill_socks_request(newconn);
- errno = rc;
- /* We may get either of these if there are no bytes to read from
- the non-blocking connection in handle_request(). Since we are
- wrapping connect() here we can't return EWOULDBLOCK/EAGAIN
- so override it with something the client will accept.*/
- if (errno == EWOULDBLOCK || errno == EAGAIN)
- errno = EINPROGRESS;
- return((rc ? -1 : 0));
- }
-}
-
-int torsocks_select_guts(SELECT_SIGNATURE, int (*original_select)(SELECT_SIGNATURE))
-{
- int nevents = 0;
- int rc = 0;
- int setevents = 0;
- int monitoring = 0;
- struct connreq *conn, *nextconn;
- fd_set mywritefds, myreadfds, myexceptfds;
-
- /* If we're not currently managing any requests we can just
- * leave here */
- if (!requests) {
- show_msg(MSGDEBUG, "No requests waiting, calling real select\n");
- return(original_select(n, readfds, writefds, exceptfds, timeout));
- }
-
- show_msg(MSGTEST, "Intercepted call to select\n");
- show_msg(MSGDEBUG, "Intercepted call to select with %d fds, "
- "0x%08x 0x%08x 0x%08x, timeout %08x\n", n,
- readfds, writefds, exceptfds, timeout);
-
- for (conn = requests; conn != NULL; conn = conn->next) {
- if ((conn->state == FAILED) || (conn->state == DONE))
- continue;
- conn->selectevents = 0;
- show_msg(MSGDEBUG, "Checking requests for socks enabled socket %d\n",
- conn->sockid);
- conn->selectevents |= (writefds ? (FD_ISSET(conn->sockid, writefds) ? WRITE : 0) : 0);
- conn->selectevents |= (readfds ? (FD_ISSET(conn->sockid, readfds) ? READ : 0) : 0);
- conn->selectevents |= (exceptfds ? (FD_ISSET(conn->sockid, exceptfds) ? EXCEPT : 0) : 0);
- if (conn->selectevents) {
- show_msg(MSGDEBUG, "Socket %d was set for events\n", conn->sockid);
- monitoring = 1;
- }
- }
-
- if (!monitoring)
- return(original_select(n, readfds, writefds, exceptfds, timeout));
-
- /* This is our select loop. In it we repeatedly call select(). We
- * pass select the same fdsets as provided by the caller except we
- * modify the fdsets for the sockets we're managing to get events
- * we're interested in (while negotiating with the socks server). When
- * events we're interested in happen we go off and process the result
- * ourselves, without returning the events to the caller. The loop
- * ends when an event which isn't one we need to handle occurs or
- * the select times out */
- do {
- /* Copy the clients fd events, we'll change them as we wish */
- if (readfds)
- memcpy(&myreadfds, readfds, sizeof(myreadfds));
- else
- FD_ZERO(&myreadfds);
- if (writefds)
- memcpy(&mywritefds, writefds, sizeof(mywritefds));
- else
- FD_ZERO(&mywritefds);
- if (exceptfds)
- memcpy(&myexceptfds, exceptfds, sizeof(myexceptfds));
- else
- FD_ZERO(&myexceptfds);
-
- /* Now enable our sockets for the events WE want to hear about */
- for (conn = requests; conn != NULL; conn = conn->next) {
- if ((conn->state == FAILED) || (conn->state == DONE) ||
- (conn->selectevents == 0))
- continue;
- /* We always want to know about socket exceptions */
- FD_SET(conn->sockid, &myexceptfds);
- /* If we're waiting for a connect or to be able to send
- * on a socket we want to get write events */
- if ((conn->state == SENDING) || (conn->state == CONNECTING))
- FD_SET(conn->sockid,&mywritefds);
- else
- FD_CLR(conn->sockid,&mywritefds);
- /* If we're waiting to receive data we want to get
- * read events */
- if (conn->state == RECEIVING)
- FD_SET(conn->sockid,&myreadfds);
- else
- FD_CLR(conn->sockid,&myreadfds);
- }
-
- nevents = original_select(n, &myreadfds, &mywritefds, &myexceptfds, timeout);
- /* If there were no events we must have timed out or had an error */
- if (nevents <= 0)
- break;
-
- /* Loop through all the sockets we're monitoring and see if
- * any of them have had events */
- for (conn = requests; conn != NULL; conn = nextconn) {
- nextconn = conn->next;
- if ((conn->state == FAILED) || (conn->state == DONE))
- continue;
- show_msg(MSGDEBUG, "Checking socket %d for events\n", conn->sockid);
- /* Clear all the events on the socket (if any), we'll reset
- * any that are necessary later. */
- setevents = 0;
- if (FD_ISSET(conn->sockid, &mywritefds)) {
- nevents--;
- setevents |= WRITE;
- show_msg(MSGDEBUG, "Socket had write event\n");
- FD_CLR(conn->sockid, &mywritefds);
- }
- if (FD_ISSET(conn->sockid, &myreadfds)) {
- nevents--;
- setevents |= READ;
- show_msg(MSGDEBUG, "Socket had write event\n");
- FD_CLR(conn->sockid, &myreadfds);
- }
- if (FD_ISSET(conn->sockid, &myexceptfds)) {
- nevents--;
- setevents |= EXCEPT;
- show_msg(MSGDEBUG, "Socket had except event\n");
- FD_CLR(conn->sockid, &myexceptfds);
- }
-
- if (!setevents) {
- show_msg(MSGDEBUG, "No events on socket %d\n", conn->sockid);
- continue;
- }
-
- if (setevents & EXCEPT)
- conn->state = FAILED;
- else
- rc = handle_request(conn);
-
- /* If the connection hasn't failed or completed there is nothing
- * to report to the client */
- if ((conn->state != FAILED) &&
- (conn->state != DONE))
- continue;
-
- /* Ok, the connection is completed, for good or for bad. We now
- * hand back the relevant events to the caller. We don't delete the
- * connection though since the caller should call connect() to
- * check the status, we delete it then */
-
- if (conn->state == FAILED) {
- /* Damn, the connection failed. Whatever the events the socket
- * was selected for we flag */
- if (conn->selectevents & EXCEPT) {
- FD_SET(conn->sockid, &myexceptfds);
- nevents++;
- }
- if (conn->selectevents & READ) {
- FD_SET(conn->sockid, &myreadfds);
- nevents++;
- }
- if (conn->selectevents & WRITE) {
- FD_SET(conn->sockid, &mywritefds);
- nevents++;
- }
- /* We should use setsockopt to set the SO_ERROR errno for this
- * socket, but this isn't allowed for some silly reason which
- * leaves us a bit hamstrung.
- * We don't delete the request so that hopefully we can
- * return the error on the socket if they call connect() on it */
- } else {
- /* The connection is done, if the client selected for
- * writing we can go ahead and signal that now (since the socket must
- * be ready for writing), otherwise we'll just let the select loop
- * come around again (since we can't flag it for read, we don't know
- * if there is any data to be read and can't be bothered checking) */
- if (conn->selectevents & WRITE) {
- FD_SET(conn->sockid, &mywritefds);
- nevents++;
- }
- }
- }
- } while (nevents == 0);
-
- show_msg(MSGDEBUG, "Finished intercepting select(), %d events\n", nevents);
-
- /* Now copy our event blocks back to the client blocks */
- if (readfds)
- memcpy(readfds, &myreadfds, sizeof(myreadfds));
- if (writefds)
- memcpy(writefds, &mywritefds, sizeof(mywritefds));
- if (exceptfds)
- memcpy(exceptfds, &myexceptfds, sizeof(myexceptfds));
-
- return(nevents);
-}
-
-int torsocks_poll_guts(POLL_SIGNATURE, int (*original_poll)(POLL_SIGNATURE))
-{
- int nevents = 0;
- int rc = 0;
- unsigned int i;
- int setevents = 0;
- int monitoring = 0;
- struct connreq *conn, *nextconn;
-
- /* If we're not currently managing any requests we can just
- * leave here */
- if (!requests)
- return(original_poll(ufds, nfds, timeout));
-
- show_msg(MSGTEST, "Intercepted call to poll\n");
- show_msg(MSGDEBUG, "Intercepted call to poll with %d fds, "
- "0x%08x timeout %d\n", nfds, ufds, timeout);
-
- for (conn = requests; conn != NULL; conn = conn->next)
- conn->selectevents = 0;
-
- /* Record what events on our sockets the caller was interested
- * in */
- for (i = 0; i < nfds; i++) {
- if (!(conn = find_socks_request(ufds[i].fd, 0)))
- continue;
- show_msg(MSGDEBUG, "Have event checks for socks enabled socket %d\n",
- conn->sockid);
- conn->selectevents = ufds[i].events;
- monitoring = 1;
- }
-
- if (!monitoring)
- return(original_poll(ufds, nfds, timeout));
-
- /* This is our poll loop. In it we repeatedly call poll(). We
- * pass select the same event list as provided by the caller except we
- * modify the events for the sockets we're managing to get events
- * we're interested in (while negotiating with the socks server). When
- * events we're interested in happen we go off and process the result
- * ourselves, without returning the events to the caller. The loop
- * ends when an event which isn't one we need to handle occurs or
- * the poll times out */
- do {
- /* Enable our sockets for the events WE want to hear about */
- for (i = 0; i < nfds; i++) {
- if (!(conn = find_socks_request(ufds[i].fd, 0)))
- continue;
-
- /* We always want to know about socket exceptions but they're
- * always returned (i.e they don't need to be in the list of
- * wanted events to be returned by the kernel */
- ufds[i].events = 0;
-
- /* If we're waiting for a connect or to be able to send
- * on a socket we want to get write events */
- if ((conn->state == SENDING) || (conn->state == CONNECTING))
- ufds[i].events |= POLLOUT;
- /* If we're waiting to receive data we want to get
- * read events */
- if (conn->state == RECEIVING)
- ufds[i].events |= POLLIN;
- }
-
- nevents = original_poll(ufds, nfds, timeout);
- /* If there were no events we must have timed out or had an error */
- if (nevents <= 0)
- break;
-
- /* Loop through all the sockets we're monitoring and see if
- * any of them have had events */
- for (conn = requests; conn != NULL; conn = nextconn) {
- nextconn = conn->next;
- if ((conn->state == FAILED) || (conn->state == DONE))
- continue;
-
- /* Find the socket in the poll list */
- for (i = 0; ((i < nfds) && (ufds[i].fd != conn->sockid)); i++)
- /* Empty Loop */;
- if (i == nfds)
- continue;
-
- show_msg(MSGDEBUG, "Checking socket %d for events\n", conn->sockid);
-
- if (!ufds[i].revents) {
- show_msg(MSGDEBUG, "No events on socket\n");
- continue;
- }
-
- /* Clear any read or write events on the socket, we'll reset
- * any that are necessary later. */
- setevents = ufds[i].revents;
- if (setevents & POLLIN) {
- show_msg(MSGDEBUG, "Socket had read event\n");
- ufds[i].revents &= ~POLLIN;
- nevents--;
- }
- if (setevents & POLLOUT) {
- show_msg(MSGDEBUG, "Socket had write event\n");
- ufds[i].revents &= ~POLLOUT;
- nevents--;
- }
- if (setevents & (POLLERR | POLLNVAL | POLLHUP))
- show_msg(MSGDEBUG, "Socket had error event\n");
-
- /* Now handle this event */
- if (setevents & (POLLERR | POLLNVAL | POLLHUP)) {
- conn->state = FAILED;
- } else {
- rc = handle_request(conn);
- }
- /* If the connection hasn't failed or completed there is nothing
- * to report to the client */
- if ((conn->state != FAILED) &&
- (conn->state != DONE))
- continue;
-
- /* Ok, the connection is completed, for good or for bad. We now
- * hand back the relevant events to the caller. We don't delete the
- * connection though since the caller should call connect() to
- * check the status, we delete it then */
-
- if (conn->state == FAILED) {
- /* Damn, the connection failed. Just copy back the error events
- * from the poll call, error events are always valid even if not
- * requested by the client */
- /* We should use setsockopt to set the SO_ERROR errno for this
- * socket, but this isn't allowed for some silly reason which
- * leaves us a bit hamstrung.
- * We don't delete the request so that hopefully we can
- * return the error on the socket if they call connect() on it */
- } else {
- /* The connection is done, if the client polled for
- * writing we can go ahead and signal that now (since the socket must
- * be ready for writing), otherwise we'll just let the select loop
- * come around again (since we can't flag it for read, we don't know
- * if there is any data to be read and can't be bothered checking) */
- if (conn->selectevents & POLLOUT) {
- setevents |= POLLOUT;
- nevents++;
- }
- }
- }
- } while (nevents == 0);
-
- show_msg(MSGDEBUG, "Finished intercepting poll(), %d events\n", nevents);
-
- /* Now restore the events polled in each of the blocks */
- for (i = 0; i < nfds; i++) {
- if (!(conn = find_socks_request(ufds[i].fd, 1)))
- continue;
- ufds[i].events = conn->selectevents;
- }
-
- return(nevents);
-}
-
-int torsocks_close_guts(CLOSE_SIGNATURE, int (*original_close)(CLOSE_SIGNATURE))
-{
- int rc;
- struct connreq *conn;
-
- /* If we're not currently managing any requests we can just
- * leave here */
- if (!requests) {
- show_msg(MSGDEBUG, "No requests waiting, calling real close\n");
- return(original_close(fd));
- }
-
- if (original_close == NULL) {
- show_msg(MSGERR, "Unresolved symbol: close\n");
- return(-1);
- }
-
- show_msg(MSGTEST, "Got call to close()\n");
- show_msg(MSGDEBUG, "Call to close(%d)\n", fd);
-
- rc = original_close(fd);
-
- /* If we have this fd in our request handling list we
- * remove it now */
- if ((conn = find_socks_request(fd, 1))) {
- show_msg(MSGDEBUG, "Call to close() received on file descriptor "
- "%d which is a connection request of status %d\n",
- conn->sockid, conn->state);
- kill_socks_request(conn);
- }
-
- return(rc);
-}
-
-/* If we are not done setting up the connection yet, return
- * -1 and ENOTCONN, otherwise call getpeername
- *
- * This is necessary since some applications, when using non-blocking connect,
- * (like ircII) use getpeername() to find out if they are connected already.
- *
- * This results in races sometimes, where the client sends data to the socket
- * before we are done with the socks connection setup. Another solution would
- * be to intercept send().
- *
- * This could be extended to actually set the peername to the peer the
- * client application has requested, but not for now.
- *
- * PP, Sat, 27 Mar 2004 11:30:23 +0100
- */
-
-int torsocks_getpeername_guts(GETPEERNAME_SIGNATURE,
- int (*original_getpeername)(GETPEERNAME_SIGNATURE))
-{
- struct connreq *conn;
- int rc;
-
- if (original_getpeername == NULL) {
- show_msg(MSGERR, "Unresolved symbol: getpeername\n");
- return(-1);
- }
-
- show_msg(MSGTEST, "Intercepted call to getpeername\n");
- show_msg(MSGDEBUG, "Call to getpeername for fd %d\n", __fd);
-
-
- rc = original_getpeername(__fd, __name, __namelen);
- if (rc == -1)
- return rc;
-
- /* Are we handling this connect? */
- if ((conn = find_socks_request(__fd, 1))) {
- /* While we are at it, we might was well try to do something useful */
- handle_request(conn);
-
- if (conn->state != DONE) {
- errno = ENOTCONN;
- return(-1);
- }
- }
- return rc;
-}
-
-#ifdef SUPPORT_RES_API
-int res_init(void)
-{
- int rc;
-
- if (!realres_init) {
- torsocks_find_library("res_init", MSGERR, realres_init);
- }
-
- show_msg(MSGTEST, "Got res_init request\n");
-
- if (realres_init == NULL) {
- show_msg(MSGERR, "Unresolved symbol: res_init\n");
- return(-1);
- }
- /* Call normal res_init */
- rc = realres_init();
-
- /* Force using TCP protocol for DNS queries */
- _res.options |= RES_USEVC;
- return(rc);
-}
-
-int EXPAND_GUTS_NAME(res_query)(RES_QUERY_SIGNATURE, int (*original_res_query)(RES_QUERY_SIGNATURE))
-{
- int rc;
-
- if (!original_res_query) {
- torsocks_find_library("res_query", MSGERR, original_res_query);
- }
-
- show_msg(MSGTEST, "Got res_query request\n");
-
- if (original_res_query == NULL) {
- show_msg(MSGERR, "Unresolved symbol: res_query\n");
- return(-1);
- }
-
- /* Ensure we force using TCP for DNS queries by calling res_init
- above if it has not already been called.*/
- if (!(_res.options & RES_INIT) || !(_res.options & RES_USEVC))
- res_init();
-
- /* Call normal res_query */
- rc = original_res_query(dname, class, type, answer, anslen);
-
- return(rc);
-}
-
-int EXPAND_GUTS_NAME(res_querydomain)(RES_QUERYDOMAIN_SIGNATURE, int (*original_res_querydomain)(RES_QUERYDOMAIN_SIGNATURE))
-{
- int rc;
-
- if (!original_res_querydomain) {
- torsocks_find_library("res_querydomain", MSGERR, original_res_querydomain);
- }
-
- show_msg(MSGDEBUG, "Got res_querydomain request\n");
-
- if (original_res_querydomain == NULL) {
- show_msg(MSGERR, "Unresolved symbol: res_querydomain\n");
- return(-1);
- }
-
- /* Ensure we force using TCP for DNS queries by calling res_init
- above if it has not already been called.*/
- if (!(_res.options & RES_INIT) || !(_res.options & RES_USEVC))
- res_init();
-
- /* Call normal res_querydomain */
- rc = original_res_querydomain(name, domain, class, type, answer, anslen);
-
- return(rc);
-}
-
-int EXPAND_GUTS_NAME(res_search)(RES_SEARCH_SIGNATURE, int (*original_res_search)(RES_SEARCH_SIGNATURE))
-{
- int rc;
-
- if (!original_res_search) {
- torsocks_find_library("res_search", MSGERR, original_res_search);
- }
-
- show_msg(MSGTEST, "Got res_search request\n");
-
- if (original_res_search == NULL) {
- show_msg(MSGERR, "Unresolved symbol: res_search\n");
- return(-1);
- }
-
- /* Ensure we force using TCP for DNS queries by calling res_init
- above if it has not already been called.*/
- if (!(_res.options & RES_INIT) || !(_res.options & RES_USEVC))
- res_init();
-
- /* Call normal res_search */
- rc = original_res_search(dname, class, type, answer, anslen);
-
- return(rc);
-}
-
-int EXPAND_GUTS_NAME(res_send)(RES_SEND_SIGNATURE, int (*original_res_send)(RES_SEND_SIGNATURE))
-{
- int rc;
-
- if (!original_res_send) {
- torsocks_find_library("res_send", MSGERR, original_res_send);
- }
-
- show_msg(MSGTEST, "Got res_send request\n");
-
- if (original_res_send == NULL) {
- show_msg(MSGERR, "Unresolved symbol: res_send\n");
- return(-1);
- }
-
- /* Ensure we force using TCP for DNS queries by calling res_init
- above if it has not already been called.*/
- if (!(_res.options & RES_INIT) || !(_res.options & RES_USEVC))
- res_init();
-
- /* Call normal res_send */
- rc = original_res_send(msg, msglen, answer, anslen);
-
- return(rc);
-}
-#endif
-
-static int deadpool_init(void)
-{
- if (pool)
- return 1;
-
- if (!config.tordns_enabled) {
- show_msg(MSGERR, "Tor DNS is disabled. Check your configuration.\n");
- return 0;
- }
-
- get_environment();
- get_config();
- pool = init_pool(config.tordns_cache_size,
- config.tordns_deadpool_range->localip,
- config.tordns_deadpool_range->localnet,
- config.defaultserver.address,
- config.defaultserver.port);
-
- if (!pool) {
- show_msg(MSGERR, "Could not initialize reserved addresses for "
- ".onion addresses. Torsocks will not work properly.\n");
- return 0;
- }
- return 1;
-}
-
-struct hostent *torsocks_gethostbyname_guts(GETHOSTBYNAME_SIGNATURE, struct hostent *(*original_gethostbyname)(GETHOSTBYNAME_SIGNATURE))
-{
- if (pool)
- return our_gethostbyname(pool, name);
- return original_gethostbyname(name);
-}
-
-struct hostent *torsocks_gethostbyaddr_guts(GETHOSTBYADDR_SIGNATURE, struct hostent *(*original_gethostbyaddr)(GETHOSTBYADDR_SIGNATURE))
-{
- if (pool)
- return our_gethostbyaddr(pool, addr, len, type);
- return original_gethostbyaddr(addr, len, type);
-}
-
-int torsocks_getaddrinfo_guts(GETADDRINFO_SIGNATURE, int (*original_getaddrinfo)(GETADDRINFO_SIGNATURE))
-{
- if (pool)
- return our_getaddrinfo(pool, node, service, hints, res);
- return original_getaddrinfo(node, service, hints, res);
-}
-
-struct hostent *torsocks_getipnodebyname_guts(GETIPNODEBYNAME_SIGNATURE, struct hostent *(*original_getipnodebyname)(GETIPNODEBYNAME_SIGNATURE))
-{
- if (pool)
- return our_getipnodebyname(pool, name, af, flags, error_num);
- return original_getipnodebyname(name, af, flags, error_num);
-}
-
-ssize_t torsocks_sendto_guts(SENDTO_SIGNATURE, ssize_t (*original_sendto)(SENDTO_SIGNATURE))
-{
- int sock_type = -1;
- unsigned int sock_type_len = sizeof(sock_type);
- struct sockaddr_in *connaddr;
-
- /* If the real sendto doesn't exist, we're stuffed */
- if (original_sendto == NULL) {
- show_msg(MSGERR, "Unresolved symbol: sendto\n");
- return(-1);
- }
-
- show_msg(MSGTEST, "Got sendto request\n");
-
- /* Get the type of the socket */
- getsockopt(s, SOL_SOCKET, SO_TYPE,
- (void *) &sock_type, &sock_type_len);
-
- show_msg(MSGDEBUG, "sockopt: %i\n", sock_type);
-
- /* If this a UDP socket then we refuse it, since it is probably a DNS
- request */
- if ((sock_type != SOCK_STREAM)) {
- show_msg(MSGERR, "sendto: Connection is a UDP or ICMP stream, may be a "
- "DNS request or other form of leak: rejecting.\n");
- return -1;
- }
-
- connaddr = (struct sockaddr_in *) to;
-
- /* If there is no address in 'to', sendto will only work if we
- already allowed the socket to connect(), so we let it through.
- Likewise if the socket is not an Internet connection. */
- if (connaddr && (connaddr->sin_family != AF_INET)) {
- show_msg(MSGDEBUG, "Connection isn't an Internet socket ignoring\n");
- }
-
- return (ssize_t) original_sendto(s, buf, len, flags, to, tolen);
-}
-
-ssize_t torsocks_sendmsg_guts(SENDMSG_SIGNATURE, ssize_t (*original_sendmsg)(SENDMSG_SIGNATURE))
-{
- int sock_type = -1;
- unsigned int sock_type_len = sizeof(sock_type);
- struct sockaddr_in *connaddr;
-
- /* If the real sendmsg doesn't exist, we're stuffed */
- if (original_sendmsg == NULL) {
- show_msg(MSGERR, "Unresolved symbol: sendmsg\n");
- return(-1);
- }
-
- show_msg(MSGTEST, "Got sendmsg request\n");
-
- /* Get the type of the socket */
- getsockopt(s, SOL_SOCKET, SO_TYPE,
- (void *) &sock_type, &sock_type_len);
-
- show_msg(MSGDEBUG, "sockopt: %i\n", sock_type);
-
- if ((sock_type != SOCK_STREAM)) {
- show_msg(MSGERR, "sendmsg: Connection is a UDP or ICMP stream, may be a "
- "DNS request or other form of leak: rejecting.\n");
- return -1;
- }
-
- connaddr = (struct sockaddr_in *) msg->msg_name;
-
- /* If there is no address in msg_name, sendmsg will only work if we
- already allowed the socket to connect(), so we let it through.
- Likewise if the socket is not an Internet connection. */
- if (connaddr && (connaddr->sin_family != AF_INET)) {
- show_msg(MSGDEBUG, "Connection isn't an Internet socket\n");
- }
-
- return (ssize_t) original_sendmsg(s, msg, flags);
-}
-
diff --git a/src/torsocks.in b/src/torsocks.in
deleted file mode 100755
index 4eaed8f..0000000
--- a/src/torsocks.in
+++ /dev/null
@@ -1,167 +0,0 @@
-#!/bin/sh
-# ***************************************************************************
-# * *
-# * *
-# * Copyright (C) 2008 by Robert Hogan *
-# * robert@xxxxxxxxxxxxxxx *
-# * Copyright (C) 2012 by Jacob Appelbaum <jacob@xxxxxxxxxxxxxx> *
-# * *
-# * 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. *
-# ***************************************************************************
-# * *
-# * This is a modified version of a source file from the Tor project. *
-# * Original copyright information follows: *
-# ***************************************************************************
-# Wrapper script for use of the torsocks(8) transparent socksification library
-#
-# There are three forms of usage for this script:
-#
-# @prefix@/bin/torsocks program [program arguments...]
-#
-# This form sets the users @LDPRELOAD@ environment variable so that torsocks(8)
-# will be loaded to socksify the application then executes the specified
-# program (with the provided arguments). The following simple example might
-# be used to telnet to www.foo.org via a torsocks.conf(5) configured socks server:
-#
-# @prefix@/bin/torsocks telnet www.foo.org
-#
-# The second form allows for torsocks(8) to be switched on and off for a
-# session (that is, it adds and removes torsocks from the @LDPRELOAD@ environment
-# variable). This form must be _sourced_ into the user's existing session
-# (and will only work with bourne shell users):
-#
-# . @prefix@/bin/torsocks on
-# telnet www.foo.org
-# . @prefix@/bin/torsocks off
-#
-# Or
-#
-# source @prefix@/bin/torsocks on
-# telnet www.foo.org
-# source @prefix@/bin/torsocks off
-#
-# The third form creates a new shell with @LDPRELOAD@ set and is achieved
-# simply by running the script with no arguments
-#
-# @prefix@/bin/torsocks
-#
-# When finished the user can simply terminate the shell with 'exit'
-#
-# This script is originally from the debian torsocks package by
-# Tamas Szerb <toma@xxxxxxxxx>
-# Modified by Robert Hogan <robert@xxxxxxxxxxxxxxx> April 16th 2006
-
-not_found () {
- echo "ERROR: $1 cannot be found in PATH." >&2
- exit 1
-}
-
-set_id () {
- echo "ERROR: $1 is set${2}id. torsocks will not work on a set${2}id executable." >&2
- exit 1
-}
-
-if [ $# = 0 ] ; then
- echo "$0: insufficient arguments"
- exit
-fi
-
-LIBDIR="@prefix@/lib/torsocks"
-LIB_NAME="libtorsocks"
-SHLIB_EXT="@SHLIB_EXT@"
-SHLIB="${LIBDIR}/${LIB_NAME}.${SHLIB_EXT}"
-
-# Check for libtorsocks and if set the 64bit variant
-if [ ! -f $SHLIB ]; then
- LIBDIR="@prefix@/lib64/torsocks"
- SHLIB="${LIBDIR}/${LIB_NAME}.${SHLIB_EXT}"
-fi
-
-# Ensure libtorsocks exists,
-if [ ! -f $SHLIB ]; then
- echo "$0: $SHLIB does not exist! Try re-installing torsocks."
- exit
-fi
-
-case "$1" in
- on)
- if [ -z "$@LDPRELOAD@" ]
- then
- export @LDPRELOAD@="${SHLIB}"
- else
- echo $@LDPRELOAD@ | grep -q "${SHLIB}" || \
- export @LDPRELOAD@="${SHLIB} $@LDPRELOAD@"
- fi
- # FIXME: This env variable is only meaningful on Mac OSX, so it would be better
- # not to set it at all on other platforms.
- export DYLD_FORCE_FLAT_NAMESPACE=1
- ;;
- off)
- #replace '/' with '\/' in @prefix@
- # escprefix=`echo '@prefix@' |sed 's/\\//\\\\\//g'`
- # export @LDPRELOAD@=`echo -n $@LDPRELOAD@ | sed "s/$escprefix\/lib\/torsocks\/libtorsocks.so \?//"`
- export @LDPRELOAD@=`echo -n $@LDPRELOAD@ | sed "s#@prefix@/lib/torsocks/libtorsocks\.@SHLIB_EXT@ *##"`
- if [ -z "$@LDPRELOAD@" ]
- then
- unset @LDPRELOAD@
- # FIXME: This env variable is only meaningful on Mac OSX, so it would be better
- # not to set it at all on other platforms.
- unset DYLD_FORCE_FLAT_NAMESPACE=1
- fi
- ;;
- show|sh)
- echo "@LDPRELOAD@=\"$@LDPRELOAD@\""
- ;;
- -h|-?)
- echo "$0: Please see torsocks(1) or read comment at top of $0"
- ;;
- --shell)
- if [ -z "$@LDPRELOAD@" ]
- then
- export @LDPRELOAD@="${SHLIB}"
- else
- echo $@LDPRELOAD@ | grep -q "${SHLIB}" || \
- export @LDPRELOAD@="${SHLIB} $@LDPRELOAD@"
- fi
- export DYLD_FORCE_FLAT_NAMESPACE=1
- echo "torsocks: new torified shell coming right up..."
- ${SHELL:-/bin/sh}
- ;;
- *)
- if [ -z "$@LDPRELOAD@" ]
- then
- export @LDPRELOAD@="${SHLIB}"
- else
- echo $@LDPRELOAD@ | grep -q "${SHLIB}" || \
- export @LDPRELOAD@="${SHLIB} $@LDPRELOAD@"
- fi
- export DYLD_FORCE_FLAT_NAMESPACE=1
-
- if [ $# -gt 0 ]
- then
- if ! which "$1" >/dev/null 2>&1; then
- not_found $1
- elif [ -u `which "$1"` ]; then
- set_id $1 u
- elif [ -g `which "$1"` ]; then
- set_id $1 g
- fi
- exec "$@"
- fi
- ;;
-esac
-
-#EOF
diff --git a/src/usewithtor.in b/src/usewithtor.in
deleted file mode 100644
index e606760..0000000
--- a/src/usewithtor.in
+++ /dev/null
@@ -1,113 +0,0 @@
-#! /bin/sh
-# ***************************************************************************
-# * *
-# * Copyright (C) 2008-2011 Robert Hogan <robert@xxxxxxxxxxxxxxx> *
-# * *
-# * 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. *
-# ***************************************************************************
-# * *
-# * This is a modified version of a source file from the Tor project. *
-# * Original copyright notice from tsocks source file follows: *
-# ***************************************************************************
-
-# Wrapper script for use of the tsocks(8) transparent socksification library
-# See the tsocks(1) and torify(1) manpages.
-
-# Copyright (c) 2004, 2006 Peter Palfrader
-# Modified by Jacob Appelbaum <jacob@xxxxxxxxxxxxx> April 16th 2006
-# Modified by Marcus Griep <marcus@xxxxxxxx> June 16 2009
-# May be distributed under the same terms as Tor itself
-
-
-# Define and ensure we have tsocks
-# XXX: what if we don't have which?
-TORSOCKS="`which torsocks`"
-PROG=
-VERBOSE=
-
-usage () {
- echo "Usage: $0 [-hv] <command> [<options>...]"
-}
-
-not_found () {
- echo "ERROR: $1 cannot be found in PATH." >&2
- exit 1
-}
-
-set_id () {
- echo "ERROR: $1 is set${2}id. usewithtor will not work on a set${2}id executable." >&2
- exit 1
-}
-
-# Check for any argument list
-if [ "$#" = 0 ]; then
- usage >&2
- exit 1
-fi
-
-while [ "$1" ]; do
- case "$1" in
- -h|--h*)
- usage
- exit 0
- ;;
- -v|--v*)
- VERBOSE=YesPlease
- shift
- ;;
- *)
- break;
- esac
-done
-
-if ! which "$1" >/dev/null 2>&1; then
- not_found $1
-elif [ -u `which "$1"` ]; then
- set_id $1 u
-elif [ -g `which "$1"` ]; then
- set_id $1 g
-fi
-
-if [ -x "$TORSOCKS" ]; then
- PROG=torsocks
-else
- echo "$0: Unable to find torsocks in PATH." >&2
- echo " Perhaps you haven't installed it?" >&2
- exit 1
-fi
-
-if [ "$VERBOSE" ]; then
- echo "We're armed with the following torsocks: $TORSOCKS"
- echo "We're attempting to use $PROG for all tor action."
-fi
-
-if [ "$PROG" = "torsocks" ]; then
- # Define our torsocks config file
- TORSOCKS_CONF_FILE="@CONFDIR@/torsocks.conf"
- export TORSOCKS_CONF_FILE
-
- # Check that we've got a torsocks config file
- if [ -r "$TORSOCKS_CONF_FILE" ]; then
- exec torsocks "$@"
- else
- echo "$0: Missing torsocks configuration file \"$TORSOCKS_CONF_FILE\" - torsocks will use defaults sensible for Tor." >&2
- exec torsocks "$@"
- fi
-fi
-
-# We should have hit an exec. If we get here, we didn't exec
-echo "$0: failed to exec $PROG $@" >&2
-exit 1
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits