commit 36194ee1b1a6b979fcf7df49a1347d7b53130645 Author: David Goulet dgoulet@ev0ke.net Date: Sun Jun 2 12:58:25 2013 -0400
Move source code to old source directory
Signed-off-by: David Goulet dgoulet@ev0ke.net --- 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@progsoc.org * + * Copyright (C) 2008-2011 Robert Hogan robert@roberthogan.net * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * * + * 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@progsoc.org * + * Copyright (C) 2008-2011 Robert Hogan robert@roberthogan.net * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +/* 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@ohmantics.net * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +/* 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@roberthogan.net * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#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@roberthogan.net * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#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@ohmantics.net * + * Copyright (C) 2011 Robert Hogan robert@roberthogan.net * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#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@progsoc.org * + * Copyright (C) 2008-2011 Robert Hogan robert@roberthogan.net * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +/* + + 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@progsoc.org * + * Copyright (C) 2008-2011 Robert Hogan robert@roberthogan.net * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +/* 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@progsoc.org * + * Copyright (C) 2008-2011 Robert Hogan robert@roberthogan.net * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +/* PreProcessor Defines */ +#include <config.h> + +/*Defining _NONSTD_SOURCE causes library and kernel calls to behave as closely +to Mac OS X 10.3's library and kernel calls as possible.*/ +#if defined(__APPLE__) || defined(__darwin__) +/* +From 'man compat' in OSX: +64-BIT COMPILATION + When compiling for 64-bit architectures, the __LP64__ macro will be defined to 1, and UNIX conformance + is always on (the _DARWIN_FEATURE_UNIX_CONFORMANCE macro will also be defined to the SUS conformance + level). Defining _NONSTD_SOURCE will cause a compilation error. +*/ +#if !defined(__LP64__) +#define _NONSTD_SOURCE 1 +#endif +#include <sys/socket.h> +#endif + + +#ifdef USE_GNU_SOURCE +#define _GNU_SOURCE +#endif + +/* Header Files */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <dlfcn.h> +#include <sys/types.h> +#include <string.h> +#include <strings.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/poll.h> +#include <sys/time.h> +#include <pwd.h> +#include <errno.h> +#include <fcntl.h> +#include <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@progsoc.org * + * Copyright (C) 2008-2011 Robert Hogan robert@roberthogan.net * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +/* socks.h - Structures used by torsocks to form SOCKS requests */ + +#ifndef _SOCKS_H + +#define _SOCKS_H 1 + +#include "parser.h" +#include "dead_pool.h" + +/* Structure representing a socks connection request */ +struct sockreq { + int8_t version; + int8_t command; + int16_t dstport; + int32_t dstip; + /* A null terminated username goes here */ +}; + +/* Structure representing a socks connection request response */ +struct sockrep { + int8_t version; + int8_t result; + int16_t ignore1; + int32_t ignore2; +}; + +/* Structure representing a socket which we are currently proxying */ +struct connreq { + /* Information about the socket and target */ + int sockid; + struct sockaddr_in connaddr; + struct sockaddr_in serveraddr; + + /* Pointer to the config entry for the socks server */ + struct serverent *path; + + /* Current state of this proxied socket */ + int state; + + /* Next state to go to when the send or receive is finished */ + int nextstate; + + /* When connections fail but an error number cannot be reported + * because the socket is non blocking we keep the connreq struct until + * the status is queried with connect() again, we then return + * this value */ + int err; + + /* Events that were set for this socket upon call to select() or + * poll() */ + int selectevents; + + /* Buffer for sending and receiving on the socket */ + unsigned int datalen; + unsigned int datadone; + char buffer[2048]; + + struct connreq *next; +}; + +/* Connection statuses */ +#define UNSTARTED 0 +#define CONNECTING 1 +#define CONNECTED 2 +#define SENDING 3 +#define RECEIVING 4 +#define SENTV4REQ 5 +#define GOTV4REQ 6 +#define SENTV5METHOD 7 +#define GOTV5METHOD 8 +#define SENTV5AUTH 9 +#define GOTV5AUTH 10 +#define SENTV5CONNECT 11 +#define GOTV5CONNECT 12 +#define DONE 13 +#define FAILED 14 + +/* Flags to indicate what events a socket was select()ed for */ +#define READ (1<<0) +#define WRITE (1<<1) +#define EXCEPT (1<<2) +#define READWRITE (READ|WRITE) +#define READWRITEEXCEPT (READ|WRITE|EXCEPT) + +/* Global Declarations */ +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@progsoc.org * + * Copyright (C) 2008-2011 Robert Hogan robert@roberthogan.net * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +/* PreProcessor Defines */ +#include <config.h> + +/*Defining _NONSTD_SOURCE causes library and kernel calls to behave as closely +to Mac OS X 10.3's library and kernel calls as possible.*/ +#if defined(__APPLE__) || defined(__darwin__) +/* +From 'man compat' in OSX: +64-BIT COMPILATION + When compiling for 64-bit architectures, the __LP64__ macro will be defined to 1, and UNIX conformance + is always on (the _DARWIN_FEATURE_UNIX_CONFORMANCE macro will also be defined to the SUS conformance + level). Defining _NONSTD_SOURCE will cause a compilation error. +*/ +#if !defined(__LP64__) +#define _NONSTD_SOURCE 1 +#endif +#include <sys/socket.h> +#endif + + +#ifdef USE_GNU_SOURCE +#define _GNU_SOURCE +#endif + +/* 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@roberthogan.net * +# * Copyright (C) 2012 by Jacob Appelbaum jacob@torproject.org * +# * * +# * 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@rulez.org +# Modified by Robert Hogan robert@roberthogan.net 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@roberthogan.net * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU General Public License as published by * +# * the Free Software Foundation; either version 2 of the License, or * +# * (at your option) any later version. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU General Public License for more details. * +# * * +# * You should have received a copy of the GNU General Public License * +# * along with this program; if not, write to the * +# * Free Software Foundation, Inc., * +#* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * +# *************************************************************************** +# * * +# * 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@appelbaum.net April 16th 2006 +# Modified by Marcus Griep marcus@griep.us 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@progsoc.org * - * Copyright (C) 2008-2011 Robert Hogan robert@roberthogan.net * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * * - * 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@progsoc.org * - * Copyright (C) 2008-2011 Robert Hogan robert@roberthogan.net * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ - -/* 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@ohmantics.net * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ - -/* 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@roberthogan.net * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ - -#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@roberthogan.net * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ - -#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@ohmantics.net * - * Copyright (C) 2011 Robert Hogan robert@roberthogan.net * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ - -#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@progsoc.org * - * Copyright (C) 2008-2011 Robert Hogan robert@roberthogan.net * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -/* - - 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@progsoc.org * - * Copyright (C) 2008-2011 Robert Hogan robert@roberthogan.net * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ - -/* 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@progsoc.org * - * Copyright (C) 2008-2011 Robert Hogan robert@roberthogan.net * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -/* PreProcessor Defines */ -#include <config.h> - -/*Defining _NONSTD_SOURCE causes library and kernel calls to behave as closely -to Mac OS X 10.3's library and kernel calls as possible.*/ -#if defined(__APPLE__) || defined(__darwin__) -/* -From 'man compat' in OSX: -64-BIT COMPILATION - When compiling for 64-bit architectures, the __LP64__ macro will be defined to 1, and UNIX conformance - is always on (the _DARWIN_FEATURE_UNIX_CONFORMANCE macro will also be defined to the SUS conformance - level). Defining _NONSTD_SOURCE will cause a compilation error. -*/ -#if !defined(__LP64__) -#define _NONSTD_SOURCE 1 -#endif -#include <sys/socket.h> -#endif - - -#ifdef USE_GNU_SOURCE -#define _GNU_SOURCE -#endif - -/* Header Files */ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <dlfcn.h> -#include <sys/types.h> -#include <string.h> -#include <strings.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <sys/poll.h> -#include <sys/time.h> -#include <pwd.h> -#include <errno.h> -#include <fcntl.h> -#include <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@progsoc.org * - * Copyright (C) 2008-2011 Robert Hogan robert@roberthogan.net * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ -/* socks.h - Structures used by torsocks to form SOCKS requests */ - -#ifndef _SOCKS_H - -#define _SOCKS_H 1 - -#include "parser.h" -#include "dead_pool.h" - -/* Structure representing a socks connection request */ -struct sockreq { - int8_t version; - int8_t command; - int16_t dstport; - int32_t dstip; - /* A null terminated username goes here */ -}; - -/* Structure representing a socks connection request response */ -struct sockrep { - int8_t version; - int8_t result; - int16_t ignore1; - int32_t ignore2; -}; - -/* Structure representing a socket which we are currently proxying */ -struct connreq { - /* Information about the socket and target */ - int sockid; - struct sockaddr_in connaddr; - struct sockaddr_in serveraddr; - - /* Pointer to the config entry for the socks server */ - struct serverent *path; - - /* Current state of this proxied socket */ - int state; - - /* Next state to go to when the send or receive is finished */ - int nextstate; - - /* When connections fail but an error number cannot be reported - * because the socket is non blocking we keep the connreq struct until - * the status is queried with connect() again, we then return - * this value */ - int err; - - /* Events that were set for this socket upon call to select() or - * poll() */ - int selectevents; - - /* Buffer for sending and receiving on the socket */ - unsigned int datalen; - unsigned int datadone; - char buffer[2048]; - - struct connreq *next; -}; - -/* Connection statuses */ -#define UNSTARTED 0 -#define CONNECTING 1 -#define CONNECTED 2 -#define SENDING 3 -#define RECEIVING 4 -#define SENTV4REQ 5 -#define GOTV4REQ 6 -#define SENTV5METHOD 7 -#define GOTV5METHOD 8 -#define SENTV5AUTH 9 -#define GOTV5AUTH 10 -#define SENTV5CONNECT 11 -#define GOTV5CONNECT 12 -#define DONE 13 -#define FAILED 14 - -/* Flags to indicate what events a socket was select()ed for */ -#define READ (1<<0) -#define WRITE (1<<1) -#define EXCEPT (1<<2) -#define READWRITE (READ|WRITE) -#define READWRITEEXCEPT (READ|WRITE|EXCEPT) - -/* Global Declarations */ -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@progsoc.org * - * Copyright (C) 2008-2011 Robert Hogan robert@roberthogan.net * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ - -/* PreProcessor Defines */ -#include <config.h> - -/*Defining _NONSTD_SOURCE causes library and kernel calls to behave as closely -to Mac OS X 10.3's library and kernel calls as possible.*/ -#if defined(__APPLE__) || defined(__darwin__) -/* -From 'man compat' in OSX: -64-BIT COMPILATION - When compiling for 64-bit architectures, the __LP64__ macro will be defined to 1, and UNIX conformance - is always on (the _DARWIN_FEATURE_UNIX_CONFORMANCE macro will also be defined to the SUS conformance - level). Defining _NONSTD_SOURCE will cause a compilation error. -*/ -#if !defined(__LP64__) -#define _NONSTD_SOURCE 1 -#endif -#include <sys/socket.h> -#endif - - -#ifdef USE_GNU_SOURCE -#define _GNU_SOURCE -#endif - -/* 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@roberthogan.net * -# * Copyright (C) 2012 by Jacob Appelbaum jacob@torproject.org * -# * * -# * 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@rulez.org -# Modified by Robert Hogan robert@roberthogan.net 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@roberthogan.net * -# * * -# * This program is free software; you can redistribute it and/or modify * -# * it under the terms of the GNU General Public License as published by * -# * the Free Software Foundation; either version 2 of the License, or * -# * (at your option) any later version. * -# * * -# * This program is distributed in the hope that it will be useful, * -# * but WITHOUT ANY WARRANTY; without even the implied warranty of * -# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * -# * GNU General Public License for more details. * -# * * -# * You should have received a copy of the GNU General Public License * -# * along with this program; if not, write to the * -# * Free Software Foundation, Inc., * -#* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * -# *************************************************************************** -# * * -# * 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@appelbaum.net April 16th 2006 -# Modified by Marcus Griep marcus@griep.us 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@lists.torproject.org