tor-commits
Threads by month
- ----- 2025 -----
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
October 2011
- 18 participants
- 1256 discussions
commit 2e51187b0f9e9b9530a9404fbee8b304edf67e5a
Author: Robert Hogan <robert(a)roberthogan.net>
Date: Mon Feb 14 21:12:11 2011 +0000
More whitespace cleanups
---
src/darwin_warts.c | 6 +++---
src/dead_pool.c | 5 +++--
src/parser.c | 13 +++++++------
src/torsocks.h | 2 +-
4 files changed, 14 insertions(+), 12 deletions(-)
diff --git a/src/darwin_warts.c b/src/darwin_warts.c
index 0a1b922..4cb86f0 100644
--- a/src/darwin_warts.c
+++ b/src/darwin_warts.c
@@ -56,9 +56,9 @@ int torsocks_select_guts(SELECT_SIGNATURE, int (*original_select)(SELECT_SIGNATU
int select(SELECT_SIGNATURE) {
if (!realselect) {
- dlerror();
- if ((realselect = dlsym(RTLD_NEXT, "select")) == NULL)
- LOAD_ERROR("select", MSGERR);
+ dlerror();
+ if ((realselect = dlsym(RTLD_NEXT, "select")) == NULL)
+ LOAD_ERROR("select", MSGERR);
}
return torsocks_select_guts(SELECT_ARGNAMES, realselect);
}
diff --git a/src/dead_pool.c b/src/dead_pool.c
index 3a6f243..c3d8b9b 100644
--- a/src/dead_pool.c
+++ b/src/dead_pool.c
@@ -28,6 +28,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
+
#include "common.h"
#include "dead_pool.h"
@@ -137,7 +138,7 @@ init_pool(unsigned int pool_size, struct in_addr deadrange_base,
return newpool;
}
-int
+int
is_dead_address(dead_pool *pool, uint32_t addr)
{
uint32_t haddr = ntohl(addr);
@@ -156,7 +157,7 @@ get_next_dead_address(dead_pool *pool, uint32_t *result)
}
}
-int
+int
store_pool_entry(dead_pool *pool, char *hostname, struct in_addr *addr)
{
int position = pool->write_pos;
diff --git a/src/parser.c b/src/parser.c
index fe4af0f..9234f8d 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -33,6 +33,7 @@
#include <stdlib.h>
#include <errno.h>
#include <config.h>
+
#include "common.h"
#include "parser.h"
@@ -277,7 +278,7 @@ static int handle_path(struct parsedfile *config, int lineno, int nowords, char
config->paths = newserver;
currentcontext = newserver;
}
-
+
return(0);
}
@@ -406,7 +407,7 @@ static int handle_port(struct parsedfile *config, int lineno, char *value) {
currentcontext->port = 0;
}
}
-
+
return(0);
}
@@ -425,7 +426,7 @@ static int handle_defuser(struct parsedfile *config, int lineno, char *value) {
} else {
currentcontext->defuser = strdup(value);
}
-
+
return(0);
}
@@ -444,7 +445,7 @@ static int handle_defpass(struct parsedfile *config, int lineno, char *value) {
} else {
currentcontext->defpass = strdup(value);
}
-
+
return(0);
}
@@ -472,7 +473,7 @@ static int handle_type(struct parsedfile *config, int lineno, char *value) {
currentcontext->type = 0;
}
}
-
+
return(0);
}
@@ -486,7 +487,7 @@ static int handle_flag(char *value)
return 0;
} else {
return -1;
- }
+ }
}
static int handle_tordns_enabled(struct parsedfile *config, int lineno,
diff --git a/src/torsocks.h b/src/torsocks.h
index 92ac35c..e75e9a8 100644
--- a/src/torsocks.h
+++ b/src/torsocks.h
@@ -24,7 +24,7 @@
#define _TORSOCKS_H 1
-#include <parser.h>
+#include "parser.h"
/* Structure representing a socks connection request */
struct sockreq {
1
0

23 Oct '11
commit a4ee2c5b39afbaa269b0458a2803aff0e336f307
Author: Robert Hogan <robert(a)roberthogan.net>
Date: Mon Feb 14 22:17:30 2011 +0000
More renaming of tsocks to torsocks
---
src/dead_pool.c | 2 +-
src/parser.c | 4 ++--
src/torsocks.h | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/dead_pool.c b/src/dead_pool.c
index c3d8b9b..bba90d3 100644
--- a/src/dead_pool.c
+++ b/src/dead_pool.c
@@ -754,7 +754,7 @@ our_getipnodebyname(dead_pool *pool, const char *name, int af, int flags,
service their request. */
if((flags & AI_V4MAPPED) == 0) {
show_msg(MSGWARN, "getipnodebyname: asked for V6 addresses only, "
- "but tsocks can't handle that\n");
+ "but torsocks can't handle that\n");
*error_num = NO_RECOVERY;
return NULL;
} else {
diff --git a/src/parser.c b/src/parser.c
index 9234f8d..592af18 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -294,7 +294,7 @@ static int handle_endpath(struct parsedfile *config, int lineno, int nowords) {
/* 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 libtsocks */
+ /* designed to do, no point in weighing down libtorsocks */
return(0);
}
@@ -366,7 +366,7 @@ static int handle_server(struct parsedfile *config, int lineno, char *value) {
ip = strsplit(NULL, &value, " ");
/* We don't verify this ip/hostname at this stage, */
- /* its resolved immediately before use in tsocks.c */
+ /* its resolved immediately before use in torsocks.c */
if (currentcontext->address == NULL)
currentcontext->address = strdup(ip);
else {
diff --git a/src/torsocks.h b/src/torsocks.h
index e75e9a8..396aa5e 100644
--- a/src/torsocks.h
+++ b/src/torsocks.h
@@ -18,7 +18,7 @@
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
-/* torsocks.h - Structures used by tsocks to form SOCKS requests */
+/* torsocks.h - Structures used by torsocks to form SOCKS requests */
#ifndef _TORSOCKS_H
1
0

[torsocks/osx] Refuse connections to local network addresses.
by hoganrobert@torproject.org 23 Oct '11
by hoganrobert@torproject.org 23 Oct '11
23 Oct '11
commit f9626fe6c27a4a9aa9bb8feb1702aec38f78147b
Author: Robert Hogan <robert(a)roberthogan.net>
Date: Sat Feb 12 14:12:04 2011 +0000
Refuse connections to local network addresses.
If a DNS request is made to a DNS server on a local network over
TCP we need to reject it. So for now, reject all attempts to connect
to servers on the local network using torsocks. If torsocks is used
with programs that expect to use local network services - this will
probably break them. I'm not aware of any.
---
src/tsocks.c | 22 ++++++++++++++--------
1 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/src/tsocks.c b/src/tsocks.c
index 02e21fc..1287d9b 100644
--- a/src/tsocks.c
+++ b/src/tsocks.c
@@ -349,10 +349,23 @@ int tsocks_connect_guts(CONNECT_SIGNATURE, int (*original_connect)(CONNECT_SIGNA
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 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, "Connection isn't a TCP stream ignoring\n");
+ show_msg(MSGDEBUG, "connect: Connection isn't IPv4, ignoring\n");
return(original_connect(__fd, __addr, __len));
}
@@ -419,13 +432,6 @@ int tsocks_connect_guts(CONNECT_SIGNATURE, int (*original_connect)(CONNECT_SIGNA
show_msg(MSGDEBUG, "Got connection request for socket %d to "
"%s\n", __fd, inet_ntoa(connaddr->sin_addr));
- /* If the address is local call original_connect */
- if (!(is_local(&config, &(connaddr->sin_addr))) &&
- !is_dead_address(pool, connaddr->sin_addr.s_addr)) {
- show_msg(MSGDEBUG, "Connection for socket %d is local\n", __fd);
- return(original_connect(__fd, __addr, __len));
- }
-
/* Ok, so its not local, we need a path to the net */
pick_server(&config, &path, &(connaddr->sin_addr), ntohs(connaddr->sin_port));
1
0

[torsocks/osx] Prevent execution of suid/sgid programs by torsocks
by hoganrobert@torproject.org 23 Oct '11
by hoganrobert@torproject.org 23 Oct '11
23 Oct '11
commit 5875e3afc294a6e92dc4b66986387b9fa3e62dfe
Author: Robert Hogan <robert(a)roberthogan.net>
Date: Sun Jan 2 13:46:39 2011 +0000
Prevent execution of suid/sgid programs by torsocks
We already do this in usewithtor. Closes off
http://code.google.com/p/torsocks/issues/detail?id=5
---
src/torsocks.in | 10 ++++++++++
1 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/src/torsocks.in b/src/torsocks.in
index d4e4f17..075a5e4 100755
--- a/src/torsocks.in
+++ b/src/torsocks.in
@@ -63,6 +63,11 @@
# Tamas Szerb <toma(a)rulez.org>
# Modified by Robert Hogan <robert(a)roberthogan.net> April 16th 2006
+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
@@ -122,6 +127,11 @@ case "$1" in
if [ $# -gt 0 ]
then
+ if [ -u `which "$1"` ]; then
+ set_id $1 u
+ elif [ -g `which "$1"` ]; then
+ set_id $1 g
+ fi
exec "$@"
fi
;;
1
0
commit 71204c20eb080350e0e4dc8eafe71fc2ea41e8be
Author: Robert Hogan <robert(a)roberthogan.net>
Date: Mon Feb 14 19:47:05 2011 +0000
Remove unused source files
Removing these supplementary utilities as they've been disabled
for some time now. They can be restored by popular demand if
necessary.
---
configure.in | 2 +-
src/Makefile.am | 11 --
src/inspectsocks.c | 200 ------------------------------------
src/saveme.c | 60 -----------
src/tsocks.announce | 13 ---
src/validateconf.c | 285 ---------------------------------------------------
6 files changed, 1 insertions(+), 570 deletions(-)
diff --git a/configure.in b/configure.in
index 9a41cf1..7cfa02c 100644
--- a/configure.in
+++ b/configure.in
@@ -1,5 +1,5 @@
dnl Process this file with autoconf to produce a configure script.
-AC_INIT(src/saveme.c)
+AC_INIT()
AC_CONFIG_HEADER(config.h)
AM_INIT_AUTOMAKE(torsocks, 0.1)
diff --git a/src/Makefile.am b/src/Makefile.am
index f0ae121..aa61a21 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -3,17 +3,6 @@
LIBS = -ldl -lc -lresolv
libdir = @libdir@/torsocks
-# Install helper programs
-#bin_PROGRAMS = validateconf inspectsocks saveme
-#validateconf_SOURCES = validateconf.c common.c parser.c
-#validateconf_CFLAGS = $(AM_CFLAGS)
-
-#inspectsocks_SOURCES = inspectsocks.c common.c
-#inspectsocks_CFLAGS = $(AM_CFLAGS)
-
-#saveme_SOURCES = saveme.c
-#saveme_CFLAGS = $(AM_CFLAGS)
-
# Install configuration file
usewithtorconfdir = $(CONFDIR)/
usewithtorconf_DATA = torsocks.conf
diff --git a/src/inspectsocks.c b/src/inspectsocks.c
deleted file mode 100644
index d93bddf..0000000
--- a/src/inspectsocks.c
+++ /dev/null
@@ -1,200 +0,0 @@
-/***************************************************************************
- * *
- * $Id: inspectsocks.c,v 1.2 2008-07-06 15:17:35 hoganrobert Exp $ *
- * *
- * Copyright (C) 2008 by Robert Hogan *
- * robert(a)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 tsocks project. *
- * Original copyright notice from tsocks source file follows: *
- * *
- ***************************************************************************/
-/*
-
- INSPECTSOCKS - Part of the tsocks package
- This utility can be used to determine the protocol
- level of a SOCKS server.
-
- Copyright (C) 2000 Shaun Clowes
-
- 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/* Global configuration variables */
-const char *torsocks_progname = "inspectsocks"; /* Name for error msgs */
-int defaultport = 1080; /* Default SOCKS port */
-
-/* Header Files */
-#include <config.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <string.h>
-#include <strings.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <errno.h>
-#include <common.h>
-
-int send_request(struct sockaddr_in *server, void *req,
- int reqlen, void *rep, int replen);
-
-int main(int argc, char *argv[]) {
- const char *usage = "Usage: <socks server name/ip> [portno]";
- char req[9];
- char resp[100];
- unsigned short int portno = defaultport;
- int ver = 0;
- int read_bytes;
- struct sockaddr_in server;
-
- if ((argc < 2) || (argc > 3)) {
- show_msg(MSGERR, "Invalid number of arguments\n");
- show_msg(MSGERR, "%s\n", usage);
- exit(1);
- }
-
- switch (argc) {
- case 3:
- portno = (unsigned short int)
- strtol(argv[2], (char **) 0, 10);
- if ((portno == 0) || (errno == EINVAL)) {
- show_msg(MSGERR, "%s\n", usage);
- exit(1);
- }
- case 2:
- if ((server.sin_addr.s_addr = resolve_ip(argv[1], 1,HOSTNAMES))
- == 0) {
- show_msg(MSGERR, "Invalid IP/host specified (%s)\n", argv[1]);
- show_msg(MSGERR, "%s\n", usage);
- exit(1);
- }
- }
-
- server.sin_family = AF_INET; /* host byte order */
- server.sin_port = htons(portno); /* short, network byte order */
- bzero(&(server.sin_zero), 8);/* zero the rest of the struct */
-
- /* Now, we send a SOCKS V5 request which happens to be */
- /* the same size as the smallest possible SOCKS V4 */
- /* request. In this packet we specify we have 7 auth */
- /* methods but specify them all as NO AUTH. */
- bzero(req, sizeof(req));
- req[0] = '\x05';
- req[1] = '\x07';
- read_bytes = send_request(&server, req,
- sizeof(req), resp, sizeof(resp));
- if (read_bytes > 0) {
- if ((int) resp[0] == 0) {
- ver = 4;
- } else if ((int) resp[0] == 5) {
- ver = 5;
- }
- if (ver != 0) {
- printf("Reply indicates server is a version "
- "%d socks server\n", ver);
- } else {
- show_msg(MSGERR, "Invalid SOCKS version reply (%d), "
- "probably not a socks server\n",
- ver);
- }
- exit(0);
- }
-
- /* Hmmm.... disconnected so try a V4 request */
- printf("Server disconnected V5 request, trying V4\n");
- req[0] = '\x04';
- req[1] = '\x01';
- read_bytes = send_request(&server, req,
- sizeof(req), resp, sizeof(resp));
- if (read_bytes > 0) {
- if ((int) resp[0] == 0) {
- ver = 4;
- }
- if (ver == 4) {
- printf("Reply indicates server is a version "
- "4 socks server\n");
- } else {
- show_msg(MSGERR, "Invalid SOCKS version reply (%d), "
- "probably not a socks server\n",
- (int) resp[0]);
- }
- exit(0);
- } else {
- show_msg(MSGERR, "Server disconnected, probably not a "
- "socks server\n");
- }
-
- return(0);
-}
-
-int send_request(struct sockaddr_in *server, void *req,
- int reqlen, void *rep, int replen) {
- int sock;
- int rc;
-
- if ((sock = socket(server->sin_family, SOCK_STREAM, 0)) < 0)
- {
- show_msg(MSGERR, "Could not create socket (%s)\n",
- strerror(errno));
- exit(1);
- }
-
- if (connect(sock, (struct sockaddr *) server,
- sizeof(struct sockaddr_in)) != -1) {
- } else {
- show_msg(MSGERR, "Connect failed! (%s)\n",
- strerror(errno));
- exit(1);
- }
-
- if (send(sock, (void *) req, reqlen,0) < 0) {
- show_msg(MSGERR, "Could not send to server (%s)\n",
- strerror(errno));
- exit(1);
- }
-
- /* Now wait for reply */
- if ((rc = recv(sock, (void *) rep, replen, 0)) < 0) {
- show_msg(MSGERR, "Could not read from server\n",
- strerror(errno));
- exit(1);
- }
-
- close(sock);
-
- return(rc);
-
-}
diff --git a/src/saveme.c b/src/saveme.c
deleted file mode 100644
index 43e490a..0000000
--- a/src/saveme.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/***************************************************************************
- * *
- * $Id: saveme.c,v 1.2 2008-07-06 15:17:35 hoganrobert Exp $ *
- * *
- * Copyright (C) 2008 by Robert Hogan *
- * robert(a)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 tsocks project. *
- * Original copyright notice from tsocks source file follows: *
- * *
- ***************************************************************************/
-/*
-
- SAVEME - Part of the tsocks package
- This program is designed to be statically linked so
- that if a user breaks their ld.so.preload file and
- cannot run any dynamically linked program it can
- delete the offending ld.so.preload file.
-
- 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <stdio.h>
-#include <unistd.h>
-
-int main() {
-
- unlink("/etc/ld.so.preload");
-
- return(0);
-}
diff --git a/src/tsocks.announce b/src/tsocks.announce
deleted file mode 100644
index 5b905e1..0000000
--- a/src/tsocks.announce
+++ /dev/null
@@ -1,13 +0,0 @@
-torsocks 1.8- Provide transparent, DNS-safe SOCKS support for Tor
-
-tsocks provides transparent network access through a SOCKS proxy. This
-is common in firewalled LAN environments where all connections to the
-internet need to pass through a SOCKS server on the firewall.
-tsocks intercepts the calls applications make to create tcp connections
-and determines if they can be directly accessed or need the SOCKS server.
-If they need the SOCKS server they connection is negotiated with the
-server transparently to the application. This allows existing applications
-to use SOCKS without recompilation or modification. tsocks is a wrapper
-library for a number of socket networking functions. Essentially it's the
-equivalent of the socksified winsock.dll libraries that are available for
-Windows.
diff --git a/src/validateconf.c b/src/validateconf.c
deleted file mode 100644
index 1d2eb44..0000000
--- a/src/validateconf.c
+++ /dev/null
@@ -1,285 +0,0 @@
-/***************************************************************************
- * *
- * $Id: validateconf.c,v 1.2 2008-07-06 15:17:35 hoganrobert Exp $ *
- * *
- * Copyright (C) 2008 by Robert Hogan *
- * robert(a)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 tsocks project. *
- * Original copyright notice from tsocks source file follows: *
- * *
- ***************************************************************************/
-/*
-
- VALIDATECONF - Part of the tsocks package
- This utility can be used to validate the torsocks.conf
- configuration file
-
- Copyright (C) 2000 Shaun Clowes
-
- 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/* Global configuration variables */
-const char *torsocks_progname = "validateconf"; /* Name for error msgs */
-
-/* Header Files */
-#include <config.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <string.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <errno.h>
-#include <common.h>
-#include <parser.h>
-
-void show_server(struct parsedfile *, struct serverent *, int);
-void show_conf(struct parsedfile *config);
-void test_host(struct parsedfile *config, char *);
-
-int main(int argc, char *argv[]) {
- const char *usage = "Usage: [-f conf file] [-t hostname/ip[:port]]";
- char *filename = NULL;
- char *testhost = NULL;
- struct parsedfile config;
- int i;
-
- if ((argc > 5) || (((argc - 1) % 2) != 0)) {
- show_msg(MSGERR, "Invalid number of arguments\n");
- show_msg(MSGERR, "%s\n", usage);
- exit(1);
- }
-
- for (i = 1; i < argc; i = i + 2) {
- if (!strcmp(argv[i], "-f")) {
- filename = argv[(i + 1)];
- } else if (!strcmp(argv[i], "-t")) {
- testhost = argv[(i + 1)];
- } else {
- show_msg(MSGERR, "Unknown option %s\n", argv[i]);
- show_msg(MSGERR, "%s\n", usage);
- exit(1);
- }
- }
-
- if (!filename)
- filename = strdup(CONF_FILE);
-
- printf("Reading configuration file %s...\n", filename);
- if (read_config(filename, &config) == 0)
- printf("... Read complete\n\n");
- else
- exit(1);
-
- /* If they specified a test host, test it, otherwise */
- /* dump the configuration */
- if (!testhost)
- show_conf(&config);
- else
- test_host(&config, testhost);
-
- return(0);
-}
-
-void test_host(struct parsedfile *config, char *host) {
- struct in_addr hostaddr;
- struct serverent *path;
- char *hostname, *port;
- char separator;
- unsigned long portno = 0;
-
- /* See if a port has been specified */
- hostname = strsplit(&separator, &host, ": \t\n");
- if (separator == ':') {
- port = strsplit(NULL, &host, " \t\n");
- if (port)
- portno = strtol(port, NULL, 0);
- }
-
- /* First resolve the host to an ip */
- if ((hostaddr.s_addr = resolve_ip(hostname, 0, 1)) == 0) {
- fprintf(stderr, "Error: Cannot resolve %s\n", host);
- return;
- } else {
- printf("Finding path for %s...\n", inet_ntoa(hostaddr));
- if (!(is_local(config, &(hostaddr)))) {
- printf("Path is local\n");
- } else {
- pick_server(config, &path, &hostaddr, portno);
- if (path == &(config->defaultserver)) {
- printf("Path is via default server:\n");
- show_server(config, path, 1);
- } else {
- printf("Host is reached via this path:\n");
- show_server(config, path, 0);
- }
- }
- }
-
- return;
-}
-
-void show_conf(struct parsedfile *config) {
- struct netent *net;
- struct serverent *server;
-
- /* Show the local networks */
- printf("=== Local networks (no socks server needed) ===\n");
- net = (config->localnets);
- while (net != NULL) {
- printf("Network: %15s ",
- inet_ntoa(net->localip));
- printf("NetMask: %15s\n",
- inet_ntoa(net->localnet));
- net = net->next;
- }
- printf("\n");
-
- /* If we have a default server configuration show it */
- printf("=== Default Server Configuration ===\n");
- if ((config->defaultserver).address != NULL) {
- show_server(config, &(config->defaultserver), 1);
- } else {
- printf("No default server specified, this is rarely a "
- "good idea\n");
- }
- printf("\n");
-
- /* Now show paths */
- if ((config->paths) != NULL) {
- server = (config->paths);
- while (server != NULL) {
- printf("=== Path (line no %d in configuration file)"
- " ===\n", server->lineno);
- show_server(config, server, 0);
- printf("\n");
- server = server->next;
- }
- }
-
- /* Show tordns configuration options */
- printf("=== TorDNS Configuration Options ===\n");
- printf("Tor DNS enabled: %s\n",
- config->tordns_enabled ? "yes" : "no");
- printf("Tor DNS deadpool range: %s/",
- inet_ntoa(config->tordns_deadpool_range->localip));
- printf("%s\n",
- inet_ntoa(config->tordns_deadpool_range->localnet));
- printf("Tor DNS cache size: %d\n", config->tordns_cache_size);
- printf("\n");
-
- return;
-}
-
-void show_server(struct parsedfile *config, struct serverent *server, int def) {
- struct in_addr res;
- struct netent *net;
-
- /* Show address */
- if (server->address != NULL)
- printf("Server: %s (%s)\n", server->address,
- ((res.s_addr = resolve_ip(server->address, 0,
- HOSTNAMES)) == 0
- ? "Invalid!" : inet_ntoa(res)));
- else
- printf("Server: ERROR! None specified\n");
-
- /* Check the server is on a local net */
- if ((server->address != NULL) && (res.s_addr != 0) &&
- (is_local(config, &res)))
- fprintf(stderr, "Error: Server is not on a network "
- "specified as local\n");
-
- /* Show port */
- printf("Port: %d\n", server->port);
-
- /* Show SOCKS type */
- printf("SOCKS type: %d\n", server->type);
-
- /* Show default username and password info */
- if (server->type == 5) {
- /* Show the default user info */
- printf("Default user: %s\n",
- (server->defuser == NULL) ?
- "Not Specified" : server->defuser);
- printf("Default pass: %s\n",
- (server->defpass == NULL) ?
- "Not Specified" : "******** (Hidden)");
- if ((server->defuser == NULL) &&
- (server->defpass != NULL))
- fprintf(stderr, "Error: Default user must be specified "
- "if default pass is specified\n");
- } else {
- if (server->defuser) printf("Default user: %s\n",
- server->defuser);
- if (server->defpass) printf("Default pass: %s\n",
- server->defpass);
- if ((server->defuser != NULL) || (server->defpass != NULL))
- fprintf(stderr, "Error: Default user and password "
- "may only be specified for version 5 "
- "servers\n");
- }
-
- /* If this is the default servers and it has reachnets, thats stupid */
- if (def) {
- if (server->reachnets != NULL) {
- fprintf(stderr, "Error: The default server has "
- "specified networks it can reach (reach statements), "
- "these statements are ignored since the "
- "default server will be tried for any network "
- "which is not specified in a reach statement "
- "for other servers\n");
- }
- } else if (server->reachnets == NULL) {
- fprintf(stderr, "Error: No reach statements specified for "
- "server, this server will never be used\n");
- } else {
- printf("This server can be used to reach:\n");
- net = server->reachnets;
- while (net != NULL) {
- printf("Network: %15s ",
- inet_ntoa(net->localip));
- printf("NetMask: %15s ",
- inet_ntoa(net->localnet));
- if (net->startport)
- printf("Ports: %5lu - %5lu",
- net->startport, net->endport);
- printf("\n");
- net = net->next;
- }
- }
-}
1
0

[torsocks/osx] Fix 'symbol res_send() was not found in any shared library'
by hoganrobert@torproject.org 23 Oct '11
by hoganrobert@torproject.org 23 Oct '11
23 Oct '11
commit 441fb10e475efa3cf9977fcf223db8344b005555
Author: Robert Hogan <robert(a)roberthogan.net>
Date: Sun Feb 13 12:41:23 2011 +0000
Fix 'symbol res_send() was not found in any shared library'
Solution found by Nicolas Pouillard (nicolas.pouillard(a)gmail.com)
However I am still not clear why this is necessary for just this
symbol on Linux.
To test that it works:
cd test/
gcc -fPIC -g -O2 -Wall -I. -o resinit resinit.c -lc -lresolv
cd ..
export TORSOCKS_DEBUG=2
torsocks test/resinit
Expected result:
12:45:33 libtorsocks(21307): Got res_send request
http://code.google.com/p/torsocks/issues/detail?id=3
---
src/expansion_table.h | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/src/expansion_table.h b/src/expansion_table.h
index 441a009..e981f5d 100644
--- a/src/expansion_table.h
+++ b/src/expansion_table.h
@@ -1,6 +1,6 @@
/***************************************************************************
* *
- * Copyright (C) 2010 alex(a)ohmantics.net *
+ * Copyright (C) 2010 Alex Rosenberg <alex(a)ohmantics.net> *
* Copyright (C) 2011 Robert Hogan <robert(a)roberthogan.net> *
* *
* This program is free software; you can redistribute it and/or modify *
@@ -76,7 +76,12 @@
/*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")
+#if defined(__APPLE__) || defined(__darwin__)
RES_FUNC (ERR, int, RES_SEND_, res_send, res_send, "res_send")
+#else
+/* It is a bit of a mystery why this is required on Linux. See http://code.google.com/p/torsocks/issues/detail?id=3 */
+RES_FUNC (ERR, int, RES_SEND_, res_send, res_send, "__res_send")
+#endif
RES_FUNC (ERR, int, RES_QUERYDOMAIN_, res_querydomain, res_querydomain, "res_querydomain")
DNS_FUNC (ERR, struct hostent *, GETHOSTBYNAME_, gethostbyname, gethostbyname, "gethostbyname")
1
0

[torsocks/osx] Rename and clean up whitespace in the signature expansion header
by hoganrobert@torproject.org 23 Oct '11
by hoganrobert@torproject.org 23 Oct '11
23 Oct '11
commit 08b0b1b24129fed869ef8a756f9102247cdb33ec
Author: Robert Hogan <robert(a)roberthogan.net>
Date: Sun Feb 13 12:14:04 2011 +0000
Rename and clean up whitespace in the signature expansion header
---
src/expansion_table.h | 125 +++++++++++++++++++++++++++++++++++++++++++++++++
src/patch_table.h | 107 ------------------------------------------
src/tsocks.c | 10 ++--
3 files changed, 130 insertions(+), 112 deletions(-)
diff --git a/src/expansion_table.h b/src/expansion_table.h
new file mode 100644
index 0000000..441a009
--- /dev/null
+++ b/src/expansion_table.h
@@ -0,0 +1,125 @@
+/***************************************************************************
+ * *
+ * Copyright (C) 2010 alex(a)ohmantics.net *
+ * Copyright (C) 2011 Robert Hogan <robert(a)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/patch_table.h b/src/patch_table.h
deleted file mode 100644
index f859613..0000000
--- a/src/patch_table.h
+++ /dev/null
@@ -1,107 +0,0 @@
-#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
-
- #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
-
- #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
- #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
-#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
-#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_FUNC (ERR, int, RES_INIT_, res_init, res_init, "res_init") */
-/* res_init takes void, so we do that one manually. */
-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/tsocks.c b/src/tsocks.c
index 1287d9b..a227469 100644
--- a/src/tsocks.c
+++ b/src/tsocks.c
@@ -113,7 +113,7 @@ static dead_pool *pool = NULL;
int (*realres_init)(void);
#endif
#define PATCH_TABLE_EXPANSION(e,r,s,n,b,m) r (*real##n)(s##SIGNATURE);
-#include "patch_table.h"
+#include "expansion_table.h"
#undef PATCH_TABLE_EXPANSION
#undef DARWIN_EXPANSION
@@ -133,14 +133,14 @@ int res_init(void);
#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 "patch_table.h"
+#include "expansion_table.h"
#undef PATCH_TABLE_EXPANSION
#undef DARWIN_EXPANSION
/* Private Function Prototypes */
/* no tsocks_res_init_guts */
#define PATCH_TABLE_EXPANSION(e,r,s,n,b,m) r tsocks_##b##_guts(s##SIGNATURE, r (*original_##b)(s##SIGNATURE));
-#include "patch_table.h"
+#include "expansion_table.h"
#undef PATCH_TABLE_EXPANSION
@@ -215,7 +215,7 @@ void tsocks_init(void)
LOAD_ERROR("res_init", MSGERR);
#endif
#define PATCH_TABLE_EXPANSION(e,r,s,n,b,m) if ((real##n = dlsym(RTLD_NEXT, m)) == NULL) LOAD_ERROR(m, MSG##e);
- #include "patch_table.h"
+ #include "expansion_table.h"
#undef PATCH_TABLE_EXPANSION
#else
lib = dlopen(LIBCONNECT, RTLD_LAZY);
@@ -311,7 +311,7 @@ static int get_config ()
} \
return tsocks_##b##_guts(s##ARGNAMES, real##n); \
}
-#include "patch_table.h"
+#include "expansion_table.h"
#undef PATCH_TABLE_EXPANSION
int tsocks_connect_guts(CONNECT_SIGNATURE, int (*original_connect)(CONNECT_SIGNATURE))
1
0
commit e482a8f18911bc05ca3cba7a9e468f7a68fd0e1c
Author: Robert Hogan <robert(a)roberthogan.net>
Date: Mon Feb 14 20:11:51 2011 +0000
Tidy up the file copyrights
---
src/common.c | 11 ++---------
src/common.h | 12 +++---------
src/darwin_warts.c | 20 ++++++++++++++++++++
src/dead_pool.c | 12 ++----------
src/dead_pool.h | 12 ++----------
src/parser.c | 11 ++---------
src/torsocks.c | 31 ++-----------------------------
src/tsocks.h | 11 ++---------
src/usewithtor.in | 5 +----
9 files changed, 36 insertions(+), 89 deletions(-)
diff --git a/src/common.c b/src/common.c
index 2f7e233..53a60b2 100644
--- a/src/common.c
+++ b/src/common.c
@@ -1,9 +1,7 @@
/***************************************************************************
* *
- * $Id: common.c,v 1.2 2008-07-06 15:17:35 hoganrobert Exp $ *
- * *
- * Copyright (C) 2008 by Robert Hogan *
- * robert(a)roberthogan.net *
+ * Copyright (C) 2000-2008 Shaun Clowes <delius(a)progsoc.org> *
+ * Copyright (C) 2008-2011 Robert Hogan <robert(a)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 *
@@ -25,11 +23,6 @@
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. *
* Copyright (c) 2007-2008, The Tor Project, Inc. *
* *
- ***************************************************************************
- * *
- * This is a modified version of a source file from the tsocks project. *
- * Original copyright notice from tsocks source file follows: *
- * *
***************************************************************************/
/*
diff --git a/src/common.h b/src/common.h
index 811e7fa..656aefb 100644
--- a/src/common.h
+++ b/src/common.h
@@ -1,9 +1,7 @@
/***************************************************************************
* *
- * $Id: common.h,v 1.2 2008-07-06 15:17:35 hoganrobert Exp $ *
- * *
- * Copyright (C) 2008 by Robert Hogan *
- * robert(a)roberthogan.net *
+ * Copyright (C) 2000-2008 Shaun Clowes <delius(a)progsoc.org> *
+ * Copyright (C) 2008-2011 Robert Hogan <robert(a)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 *
@@ -19,12 +17,8 @@
* 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 tsocks project. *
- * Original copyright notice from tsocks source file follows: *
- * *
***************************************************************************/
+
/* Common functions provided in common.c */
/* GCC has several useful attributes. */
#include <sys/types.h>
diff --git a/src/darwin_warts.c b/src/darwin_warts.c
index c35ed8b..2222cf2 100644
--- a/src/darwin_warts.c
+++ b/src/darwin_warts.c
@@ -1,3 +1,23 @@
+/***************************************************************************
+ * *
+ * Copyright (C) 2010 Alex Rosenberg <alex(a)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
diff --git a/src/dead_pool.c b/src/dead_pool.c
index 13fadc7..3a6f243 100644
--- a/src/dead_pool.c
+++ b/src/dead_pool.c
@@ -1,9 +1,7 @@
/***************************************************************************
* *
- * $Id: dead_pool.c,v 1.3 2008-07-07 20:04:49 hoganrobert Exp $ *
- * *
- * Copyright (C) 2008 by Robert Hogan *
- * robert(a)roberthogan.net *
+ * Copyright (C) 2005 Total Information Security Ltd. *
+ * Copyright (C) 2008-2011 Robert Hogan <robert(a)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 *
@@ -19,12 +17,6 @@
* 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 TIA tor-dns . *
- * patch for tsocks. (See the patches directory for more info.) *
- * The original source file contained no copyright notice. *
- * *
***************************************************************************/
#include <stdio.h>
diff --git a/src/dead_pool.h b/src/dead_pool.h
index 9c1d453..d6e3e10 100644
--- a/src/dead_pool.h
+++ b/src/dead_pool.h
@@ -1,9 +1,7 @@
/***************************************************************************
* *
- * $Id: dead_pool.h,v 1.4 2008-07-06 15:29:10 hoganrobert Exp $ *
- * *
- * Copyright (C) 2008 by Robert Hogan *
- * robert(a)roberthogan.net *
+ * Copyright (C) 2005 Total Information Security Ltd. *
+ * Copyright (C) 2008-2011 Robert Hogan <robert(a)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 *
@@ -19,12 +17,6 @@
* 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 TIA tor-dns . *
- * patch for tsocks. (See the patches directory for more info.) *
- * The original source file contained no copyright notice. *
- * *
***************************************************************************/
#ifndef _DEAD_POOL_H
diff --git a/src/parser.c b/src/parser.c
index 5619ed2..fe4af0f 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -1,9 +1,7 @@
/***************************************************************************
* *
- * $Id: parser.c,v 1.3 2008-07-06 15:17:35 hoganrobert Exp $ *
- * *
- * Copyright (C) 2008 by Robert Hogan *
- * robert(a)roberthogan.net *
+ * Copyright (C) 2000-2008 Shaun Clowes <delius(a)progsoc.org> *
+ * Copyright (C) 2008-2011 Robert Hogan <robert(a)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 *
@@ -19,11 +17,6 @@
* 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 tsocks project. *
- * Original copyright notice from tsocks source file follows: *
- * (Source file contained no copyright information.) *
***************************************************************************/
/*
diff --git a/src/torsocks.c b/src/torsocks.c
index a227469..538a182 100644
--- a/src/torsocks.c
+++ b/src/torsocks.c
@@ -1,9 +1,8 @@
/***************************************************************************
* *
- * $Id: tsocks.c,v 1.5 2008-07-06 15:17:35 hoganrobert Exp $ *
* *
- * Copyright (C) 2008 by Robert Hogan *
- * robert(a)roberthogan.net *
+ * Copyright (C) 2000-2008 Shaun Clowes <delius(a)progsoc.org> *
+ * Copyright (C) 2008-2011 Robert Hogan <robert(a)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 *
@@ -19,33 +18,7 @@
* 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 tsocks project. *
- * Original copyright notice from tsocks source file follows: *
- * *
***************************************************************************/
-/*
-
- TSOCKS - Wrapper library for transparent SOCKS
-
- Copyright (C) 2000 Shaun Clowes
-
- 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
/* PreProcessor Defines */
#include <config.h>
diff --git a/src/tsocks.h b/src/tsocks.h
index 392bccf..b637331 100644
--- a/src/tsocks.h
+++ b/src/tsocks.h
@@ -1,9 +1,7 @@
/***************************************************************************
* *
- * $Id: tsocks.h,v 1.2 2008-07-06 15:17:35 hoganrobert Exp $ *
- * *
- * Copyright (C) 2008 by Robert Hogan *
- * robert(a)roberthogan.net *
+ * Copyright (C) 2000-2008 Shaun Clowes <delius(a)progsoc.org> *
+ * Copyright (C) 2008-2011 Robert Hogan <robert(a)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 *
@@ -19,11 +17,6 @@
* 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 tsocks project. *
- * Original copyright notice from tsocks source file follows: *
- * (Original file contained no copyright information) *
***************************************************************************/
/* tsocks.h - Structures used by tsocks to form SOCKS requests */
diff --git a/src/usewithtor.in b/src/usewithtor.in
index ac25fe9..0a1e42d 100644
--- a/src/usewithtor.in
+++ b/src/usewithtor.in
@@ -1,10 +1,7 @@
#! /bin/sh
# ***************************************************************************
# * *
-# * $Id: usewithtor.in,v 1.3 2008-07-06 15:17:35 hoganrobert Exp $*
-# * *
-# * Copyright (C) 2008 by Robert Hogan *
-# * robert(a)roberthogan.net *
+# * Copyright (C) 2008-2011 Robert Hogan <robert(a)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 *
1
0
commit 896c413ef4b226caa45e20c4f8bb89b5ed057d6e
Author: Robert Hogan <robert(a)roberthogan.net>
Date: Mon Feb 14 20:02:41 2011 +0000
Rename tsocks.c to torsocks.c
---
configure.in | 14 +-
src/Makefile.am | 2 +-
src/torsocks.c | 1757 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/tsocks.c | 1757 -------------------------------------------------------
4 files changed, 1765 insertions(+), 1765 deletions(-)
diff --git a/configure.in b/configure.in
index 7cfa02c..a962b55 100644
--- a/configure.in
+++ b/configure.in
@@ -4,12 +4,12 @@ AC_CONFIG_HEADER(config.h)
AM_INIT_AUTOMAKE(torsocks, 0.1)
-dnl Our default prefix is /usr/ since most people will be using tsocks
+dnl Our default prefix is /usr/ since most people will be using torsocks
dnl on Linux systems and that /usr/local/ stuff annoys them
dnl AC_PREFIX_DEFAULT(/usr)
dnl if libdir hasn't been set by the user default it to /lib since
-dnl tsocks needs to be on the root partition if put in the
+dnl torsocks needs to be on the root partition if put in the
dnl /etc/ld.so.preload file
dnl test "$libdir" = "\${exec_prefix}/lib" && libdir="/lib"
@@ -19,13 +19,13 @@ AC_ARG_ENABLE(socksdns,
AC_ARG_ENABLE(tordns,
[ --disable-tordns don't override name lookup calls to use SOCKS ])
AC_ARG_ENABLE(debug,
-[ --disable-debug disable ALL error messages from tsocks ])
+[ --disable-debug disable ALL error messages from torsocks ])
AC_ARG_ENABLE(oldmethod,
[ --enable-oldmethod use the old method to override connect ])
AC_ARG_ENABLE(hostnames,
[ --enable-hostnames enable hostname lookups for socks servers ])
AC_ARG_ENABLE(envconf,
-[ --disable-envconf do not allow TSOCKS_CONF_FILE to specify configuration file ])
+[ --disable-envconf do not allow TORSOCKS_CONF_FILE to specify configuration file ])
dnl -----------------------------------
dnl Get hostname and other information.
@@ -108,11 +108,11 @@ AC_CHECK_FUNC(inet_aton, AC_DEFINE([HAVE_INET_ATON],[],[Description]), [
LIBS="${LIBS} -lnsl" ], [
AC_MSG_ERROR("Neither inet_aton or inet_addr present")])])])
-dnl Look for gethostbyname (needed by tsocks and inspectsocks)
+dnl Look for gethostbyname (needed by torsocks)
AC_CHECK_FUNC(gethostbyname, AC_DEFINE([HAVE_GETHOSTBYNAME],[],[Description]), [
AC_CHECK_LIB(xnet, gethostbyname, AC_DEFINE([HAVE_GETHOSTBYNAME],[],[Description]), [
AC_MSG_ERROR(["gethostbyname not found, name lookups in " \
- "tsocks and inspectsocks disabled"])])])
+ "torsocks disabled"])])])
dnl The simple programs (saveme and inspectsocks) have no further
dnl requirements, so save the libs needed here and use them in the
@@ -539,7 +539,7 @@ NAMES='s, msg, flags'
AC_DEFINE_UNQUOTED(SENDMSG_SIGNATURE, [${PROTO}], [Description])
AC_DEFINE_UNQUOTED([SENDMSG_ARGNAMES],[${NAMES}],[Argument names])
-dnl Output the special librarys (libdl etc needed for tsocks)
+dnl Output the special librarys (libdl etc needed for torsocks)
SPECIALLIBS=${LIBS}
AC_SUBST(SPECIALLIBS)
LIBS=${SIMPLELIBS}
diff --git a/src/Makefile.am b/src/Makefile.am
index aa61a21..134dc42 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -26,7 +26,7 @@ torsocksconfmanpage_DATA = torsocks.conf.5
# Install main library to $(prefix)/lib/tor (must match torsocks.in)
lib_LTLIBRARIES = libtorsocks.la
-libtorsocks_la_SOURCES = tsocks.c common.c parser.c dead_pool.c darwin_warts.c
+libtorsocks_la_SOURCES = torsocks.c common.c parser.c dead_pool.c darwin_warts.c
libtorsocks_la_LDFLAGS = -version-info 1:0:0
#libtorsocks_la_CFLAGS = -nostartfiles
diff --git a/src/torsocks.c b/src/torsocks.c
new file mode 100644
index 0000000..a227469
--- /dev/null
+++ b/src/torsocks.c
@@ -0,0 +1,1757 @@
+/***************************************************************************
+ * *
+ * $Id: tsocks.c,v 1.5 2008-07-06 15:17:35 hoganrobert Exp $ *
+ * *
+ * Copyright (C) 2008 by Robert Hogan *
+ * robert(a)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 tsocks project. *
+ * Original copyright notice from tsocks source file follows: *
+ * *
+ ***************************************************************************/
+/*
+
+ TSOCKS - Wrapper library for transparent SOCKS
+
+ Copyright (C) 2000 Shaun Clowes
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, 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 <common.h>
+#include <pthread.h>
+#include <stdarg.h>
+#if !defined(__APPLE__) && !defined(__darwin__)
+#include <sys/socket.h>
+#endif
+#include <resolv.h>
+#include <parser.h>
+#include <tsocks.h>
+#include "dead_pool.h"
+
+/* Some function names are macroized on Darwin. Allow those names
+ to expand accordingly. */
+#define EXPAND_GUTS(x) tsocks_##x##_guts
+#define EXPAND_GUTS_NAME(x) EXPAND_GUTS(x)
+
+/* Global Declarations */
+static dead_pool *pool = NULL;
+
+/* Function prototypes for original functions that we patch */
+#ifdef SUPPORT_RES_API
+int (*realres_init)(void);
+#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 struct connreq *requests = NULL;
+static int suid = 0;
+static char *conffile = NULL;
+static volatile int tsocks_init_complete = 0;
+
+/* Exported Function Prototypes */
+void __attribute__ ((constructor)) tsocks_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 tsocks_res_init_guts */
+#define PATCH_TABLE_EXPANSION(e,r,s,n,b,m) r tsocks_##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 connect_server(struct connreq *conn);
+static int send_socks_request(struct connreq *conn);
+static struct connreq *new_socks_request(int sockid, struct sockaddr_in *connaddr,
+ struct sockaddr_in *serveraddr,
+ struct serverent *path);
+static void kill_socks_request(struct connreq *conn);
+static int handle_request(struct connreq *conn);
+static struct connreq *find_socks_request(int sockid, int includefailed);
+static int connect_server(struct connreq *conn);
+static int send_socks_request(struct connreq *conn);
+static int send_socksv4_request(struct connreq *conn);
+static int send_socksv5_method(struct connreq *conn);
+static int send_socksv5_connect(struct connreq *conn);
+static int send_buffer(struct connreq *conn);
+static int recv_buffer(struct connreq *conn);
+static int read_socksv5_method(struct connreq *conn);
+static int read_socksv4_req(struct connreq *conn);
+static int read_socksv5_connect(struct connreq *conn);
+static int read_socksv5_auth(struct connreq *conn);
+static int deadpool_init(void);
+static int send_socksv4a_request(struct connreq *conn, const char *onion_host);
+
+static pthread_mutex_t tsocks_init_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void tsocks_init(void)
+{
+#define LOAD_ERROR(s,l) { \
+ char *error; \
+ error = dlerror(); \
+ show_msg(l, "The symbol %s() was not found in any shared " \
+ "library. The error reported was: %s!\n", s, \
+ (error)?error:"not found"); \
+ dlerror(); \
+ }
+ pthread_mutex_lock(&tsocks_init_mutex);
+
+ /* We only need to be called once */
+ if (tsocks_init_complete)
+ return;
+
+ /* Not strictly true yet, but prevents us getting called while still in progress.*/
+ /* This has been observed on Snow Leopard for instance. */
+ tsocks_init_complete = 1;
+
+ show_msg(MSGWARN, "In tsocks_init \n");
+
+ get_environment();
+ get_config();
+
+ show_msg(MSGWARN, "In tsocks_init after env/config\n");
+
+#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
+ if ((realres_init = dlsym(RTLD_NEXT, "res_init")) == NULL)
+ LOAD_ERROR("res_init", MSGERR);
+ #endif
+ #define PATCH_TABLE_EXPANSION(e,r,s,n,b,m) if ((real##n = dlsym(RTLD_NEXT, m)) == NULL) LOAD_ERROR(m, MSG##e);
+ #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);
+ }
+
+ tsocks_init_complete=1;
+ pthread_mutex_unlock(&tsocks_init_mutex);
+
+ show_msg(MSGWARN, "Exit tsocks_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, 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 tsocks_res_init_guts */
+#define PATCH_TABLE_EXPANSION(e,r,s,n,b,m) \
+ r n(s##SIGNATURE) { \
+ if (!real##n) { \
+ dlerror(); \
+ if ((real##n = dlsym(RTLD_NEXT, m)) == NULL) \
+ LOAD_ERROR(m, MSG##e); \
+ } \
+ return tsocks_##b##_guts(s##ARGNAMES, real##n); \
+ }
+#include "expansion_table.h"
+#undef PATCH_TABLE_EXPANSION
+
+int tsocks_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;
+
+ /* See comment in close() */
+ if (!tsocks_init_complete)
+ tsocks_init();
+
+ /* 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(MSGDEBUG, "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 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 "
+ "tsocks 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, HOSTNAMES)) == -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;
+ return((rc ? -1 : 0));
+ }
+}
+
+int tsocks_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));
+ }
+
+ if (!tsocks_init_complete)
+ tsocks_init();
+
+ 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 tsocks_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));
+
+ if (!tsocks_init_complete)
+ tsocks_init();
+
+ 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 tsocks_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 we are called before this symbol has been dlopened then try
+ loading symbols now. This is a workaround for a problem I don't
+ really understand and have only encountered when using torsocks
+ with svn on Fedora 10, so definitely a hack. */
+ if (!tsocks_init_complete)
+ tsocks_init();
+
+ if (original_close == NULL) {
+ show_msg(MSGERR, "Unresolved symbol: close\n");
+ return(-1);
+ }
+
+ 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 tsocks_getpeername_guts(GETPEERNAME_SIGNATURE,
+ int (*original_getpeername)(GETPEERNAME_SIGNATURE))
+{
+ struct connreq *conn;
+ int rc;
+
+ /* See comment in close() */
+ if (!tsocks_init_complete)
+ tsocks_init();
+
+ if (original_getpeername == NULL) {
+ show_msg(MSGERR, "Unresolved symbol: getpeername\n");
+ return(-1);
+ }
+
+ 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;
+}
+
+static struct connreq *new_socks_request(int sockid, struct sockaddr_in *connaddr,
+ struct sockaddr_in *serveraddr,
+ struct serverent *path)
+{
+ struct connreq *newconn;
+
+ if ((newconn = malloc(sizeof(*newconn))) == NULL) {
+ /* Could not malloc, we're stuffed */
+ show_msg(MSGERR, "Could not allocate memory for new socks request\n");
+ return(NULL);
+ }
+
+ /* Add this connection to be proxied to the list */
+ memset(newconn, 0x0, sizeof(*newconn));
+ newconn->sockid = sockid;
+ newconn->state = UNSTARTED;
+ newconn->path = path;
+ memcpy(&(newconn->connaddr), connaddr, sizeof(newconn->connaddr));
+ memcpy(&(newconn->serveraddr), serveraddr, sizeof(newconn->serveraddr));
+ newconn->next = requests;
+ requests = newconn;
+
+ return(newconn);
+}
+
+static void kill_socks_request(struct connreq *conn)
+{
+ struct connreq *connnode;
+
+ if (requests == conn)
+ requests = conn->next;
+ else {
+ for (connnode = requests; connnode != NULL; connnode = connnode->next) {
+ if (connnode->next == conn) {
+ connnode->next = conn->next;
+ break;
+ }
+ }
+ }
+
+ free(conn);
+}
+
+static struct connreq *find_socks_request(int sockid, int includefinished)
+{
+ struct connreq *connnode;
+
+ for (connnode = requests; connnode != NULL; connnode = connnode->next) {
+ if (connnode->sockid == sockid) {
+ if (((connnode->state == FAILED) || (connnode->state == DONE)) &&
+ !includefinished)
+ break;
+ else
+ return(connnode);
+ }
+ }
+
+ return(NULL);
+}
+
+static int handle_request(struct connreq *conn)
+{
+ int rc = 0;
+ int i = 0;
+
+ show_msg(MSGDEBUG, "Beginning handle loop for socket %d\n", conn->sockid);
+
+ while ((rc == 0) &&
+ (conn->state != FAILED) &&
+ (conn->state != DONE) &&
+ (i++ < 20)) {
+ show_msg(MSGDEBUG, "In request handle loop for socket %d, "
+ "current state of request is %d\n", conn->sockid,
+ conn->state);
+ switch(conn->state) {
+ case UNSTARTED:
+ case CONNECTING:
+ rc = connect_server(conn);
+ break;
+ case CONNECTED:
+ rc = send_socks_request(conn);
+ break;
+ case SENDING:
+ rc = send_buffer(conn);
+ break;
+ case RECEIVING:
+ rc = recv_buffer(conn);
+ break;
+ case SENTV4REQ:
+ show_msg(MSGDEBUG, "Receiving reply to SOCKS V4 connect request\n");
+ conn->datalen = sizeof(struct sockrep);
+ conn->datadone = 0;
+ conn->state = RECEIVING;
+ conn->nextstate = GOTV4REQ;
+ break;
+ case GOTV4REQ:
+ rc = read_socksv4_req(conn);
+ break;
+ case SENTV5METHOD:
+ show_msg(MSGDEBUG, "Receiving reply to SOCKS V5 method negotiation\n");
+ conn->datalen = 2;
+ conn->datadone = 0;
+ conn->state = RECEIVING;
+ conn->nextstate = GOTV5METHOD;
+ break;
+ case GOTV5METHOD:
+ rc = read_socksv5_method(conn);
+ break;
+ case SENTV5AUTH:
+ show_msg(MSGDEBUG, "Receiving reply to SOCKS V5 authentication negotiation\n");
+ conn->datalen = 2;
+ conn->datadone = 0;
+ conn->state = RECEIVING;
+ conn->nextstate = GOTV5AUTH;
+ break;
+ case GOTV5AUTH:
+ rc = read_socksv5_auth(conn);
+ break;
+ case SENTV5CONNECT:
+ show_msg(MSGDEBUG, "Receiving reply to SOCKS V5 connect request\n");
+ conn->datalen = 10;
+ conn->datadone = 0;
+ conn->state = RECEIVING;
+ conn->nextstate = GOTV5CONNECT;
+ break;
+ case GOTV5CONNECT:
+ rc = read_socksv5_connect(conn);
+ break;
+ }
+ conn->err = errno;
+ }
+
+ if (i == 20)
+ show_msg(MSGERR, "Ooops, state loop while handling request %d\n",
+ conn->sockid);
+
+ show_msg(MSGDEBUG, "Handle loop completed for socket %d in state %d, "
+ "returning %d\n", conn->sockid, conn->state, rc);
+ return(rc);
+}
+
+static int connect_server(struct connreq *conn)
+{
+ int rc;
+
+ /* Connect this socket to the socks server */
+ show_msg(MSGDEBUG, "Connecting to %s port %d\n",
+ inet_ntoa(conn->serveraddr.sin_addr), ntohs(conn->serveraddr.sin_port));
+
+ rc = realconnect(conn->sockid, (CONNECT_SOCKARG) &(conn->serveraddr),
+ sizeof(conn->serveraddr));
+
+ show_msg(MSGDEBUG, "Connect returned %d, errno is %d\n", rc, errno);
+ if (rc && errno == EISCONN) {
+ rc = 0;
+ show_msg(MSGDEBUG, "Socket %d already connected to SOCKS server\n", conn->sockid);
+ conn->state = CONNECTED;
+ } else if (rc) {
+ if (errno != EINPROGRESS) {
+ show_msg(MSGERR, "Error %d attempting to connect to SOCKS "
+ "server (%s)\n", errno, strerror(errno));
+ conn->state = FAILED;
+ } else {
+ show_msg(MSGDEBUG, "Connection in progress\n");
+ conn->state = CONNECTING;
+ }
+ } else {
+ show_msg(MSGDEBUG, "Socket %d connected to SOCKS server\n", conn->sockid);
+ conn->state = CONNECTED;
+ }
+
+ return((rc ? errno : 0));
+}
+
+static int send_socks_request(struct connreq *conn)
+{
+ int rc = 0;
+
+ if (conn->path->type == 4) {
+ char *name = get_pool_entry(pool, &(conn->connaddr.sin_addr));
+ if(name != NULL)
+ rc = send_socksv4a_request(conn,name);
+ else
+ rc = send_socksv4_request(conn);
+ } else
+ rc = send_socksv5_method(conn);
+ return(rc);
+}
+
+static int send_socksv4a_request(struct connreq *conn,const char *onion_host)
+{
+ struct passwd *user;
+ struct sockreq *thisreq;
+ int endOfUser;
+ /* Determine the current username */
+ user = getpwuid(getuid());
+
+ thisreq = (struct sockreq *) conn->buffer;
+ endOfUser=sizeof(struct sockreq) +
+ (user == NULL ? 0 : strlen(user->pw_name)) + 1;
+
+ /* Check the buffer has enough space for the request */
+ /* and the user name */
+ conn->datalen = endOfUser+
+ (onion_host == NULL ? 0 : strlen(onion_host)) + 1;
+ if (sizeof(conn->buffer) < conn->datalen) {
+ show_msg(MSGERR, "The SOCKS username is too long");
+ conn->state = FAILED;
+ return(ECONNREFUSED);
+ }
+
+ /* Create the request */
+ thisreq->version = 4;
+ thisreq->command = 1;
+ thisreq->dstport = conn->connaddr.sin_port;
+ thisreq->dstip = htonl(1);
+
+ /* Copy the username */
+ strcpy((char *) thisreq + sizeof(struct sockreq),
+ (user == NULL ? "" : user->pw_name));
+
+ /* Copy the onion host */
+ strcpy((char *) thisreq + endOfUser,
+ (onion_host == NULL ? "" : onion_host));
+
+ conn->datadone = 0;
+ conn->state = SENDING;
+ conn->nextstate = SENTV4REQ;
+
+ return(0);
+}
+
+static int send_socksv4_request(struct connreq *conn)
+{
+ struct passwd *user;
+ struct sockreq *thisreq;
+
+ /* Determine the current username */
+ user = getpwuid(getuid());
+
+ thisreq = (struct sockreq *) conn->buffer;
+
+ /* Check the buffer has enough space for the request */
+ /* and the user name */
+ conn->datalen = sizeof(struct sockreq) +
+ (user == NULL ? 0 : strlen(user->pw_name)) + 1;
+ if (sizeof(conn->buffer) < conn->datalen) {
+ show_msg(MSGERR, "The SOCKS username is too long");
+ conn->state = FAILED;
+ return(ECONNREFUSED);
+ }
+
+ /* Create the request */
+ thisreq->version = 4;
+ thisreq->command = 1;
+ thisreq->dstport = conn->connaddr.sin_port;
+ thisreq->dstip = conn->connaddr.sin_addr.s_addr;
+
+ /* Copy the username */
+ strcpy((char *) thisreq + sizeof(struct sockreq),
+ (user == NULL ? "" : user->pw_name));
+
+ conn->datadone = 0;
+ conn->state = SENDING;
+ conn->nextstate = SENTV4REQ;
+
+ return(0);
+}
+
+static int send_socksv5_method(struct connreq *conn)
+{
+ char verstring[] = { 0x05, /* Version 5 SOCKS */
+ 0x02, /* No. Methods */
+ 0x00, /* Null Auth */
+ 0x02 }; /* User/Pass Auth */
+
+ show_msg(MSGDEBUG, "Constructing V5 method negotiation\n");
+ conn->state = SENDING;
+ conn->nextstate = SENTV5METHOD;
+ memcpy(conn->buffer, verstring, sizeof(verstring));
+ conn->datalen = sizeof(verstring);
+ conn->datadone = 0;
+
+ return(0);
+}
+
+static int send_socksv5_connect(struct connreq *conn)
+{
+ int namelen = 0;
+ char *name = NULL;
+ char constring[] = { 0x05, /* Version 5 SOCKS */
+ 0x01, /* Connect request */
+ 0x00, /* Reserved */
+ 0x01 }; /* IP Version 4 */
+
+ show_msg(MSGDEBUG, "Constructing V5 connect request\n");
+ conn->datadone = 0;
+ conn->state = SENDING;
+ conn->nextstate = SENTV5CONNECT;
+ memcpy(conn->buffer, constring, sizeof(constring));
+ conn->datalen = sizeof(constring);
+
+ show_msg(MSGDEBUG, "send_socksv5_connect: looking for: %s\n",
+ inet_ntoa(conn->connaddr.sin_addr));
+
+ name = get_pool_entry(pool, &(conn->connaddr.sin_addr));
+ if(name != NULL) {
+ namelen = strlen(name);
+ if(namelen > 255) /* "Can't happen" */
+ name = NULL;
+ }
+ if(name != NULL) {
+ show_msg(MSGDEBUG, "send_socksv5_connect: found it!\n");
+ /* Substitute the domain name from the pool into the SOCKS request. */
+ conn->buffer[3] = 0x03; /* Change the ATYP field */
+ conn->buffer[4] = namelen; /* Length of name */
+ conn->datalen++;
+ memcpy(&conn->buffer[conn->datalen], name, namelen);
+ conn->datalen += namelen;
+ } else {
+ show_msg(MSGDEBUG, "send_socksv5_connect: ip address not found\n");
+ /* Use the raw IP address */
+ memcpy(&conn->buffer[conn->datalen], &(conn->connaddr.sin_addr.s_addr),
+ sizeof(conn->connaddr.sin_addr.s_addr));
+ conn->datalen += sizeof(conn->connaddr.sin_addr.s_addr);
+ }
+ memcpy(&conn->buffer[conn->datalen], &(conn->connaddr.sin_port),
+ sizeof(conn->connaddr.sin_port));
+ conn->datalen += sizeof(conn->connaddr.sin_port);
+
+ return(0);
+}
+
+static int send_buffer(struct connreq *conn)
+{
+ int rc = 0;
+
+ show_msg(MSGDEBUG, "Writing to server (sending %d bytes)\n", conn->datalen);
+ while ((rc == 0) && (conn->datadone != conn->datalen)) {
+ rc = send(conn->sockid, conn->buffer + conn->datadone,
+ conn->datalen - conn->datadone, 0);
+ if (rc > 0) {
+ conn->datadone += rc;
+ rc = 0;
+ } else {
+ if (errno != EWOULDBLOCK)
+ show_msg(MSGDEBUG, "Write failed, %s\n", strerror(errno));
+ rc = errno;
+ }
+ }
+
+ if (conn->datadone == conn->datalen)
+ conn->state = conn->nextstate;
+
+ show_msg(MSGDEBUG, "Sent %d bytes of %d bytes in buffer, return code is %d\n",
+ conn->datadone, conn->datalen, rc);
+ return(rc);
+}
+
+static int recv_buffer(struct connreq *conn)
+{
+ int rc = 0;
+
+ show_msg(MSGDEBUG, "Reading from server (expecting %d bytes)\n", conn->datalen);
+ while ((rc == 0) && (conn->datadone != conn->datalen)) {
+ rc = recv(conn->sockid, conn->buffer + conn->datadone,
+ conn->datalen - conn->datadone, 0);
+ if (rc > 0) {
+ conn->datadone += rc;
+ rc = 0;
+ } else if (rc == 0) {
+ show_msg(MSGDEBUG, "Peer has shutdown but we only read %d of %d bytes.\n",
+ conn->datadone, conn->datalen);
+ rc = ENOTCONN; /* ENOTCONN seems like the most fitting error message */
+ } else {
+ if (errno != EWOULDBLOCK)
+ show_msg(MSGDEBUG, "Read failed, %s\n", strerror(errno));
+ rc = errno;
+ }
+ }
+
+ if (conn->datadone == conn->datalen)
+ conn->state = conn->nextstate;
+
+ show_msg(MSGDEBUG, "Received %d bytes of %d bytes expected, return code is %d\n",
+ conn->datadone, conn->datalen, rc);
+ return(rc);
+}
+
+static int read_socksv5_method(struct connreq *conn)
+{
+ struct passwd *nixuser;
+ char *uname, *upass;
+
+ /* See if we offered an acceptable method */
+ if (conn->buffer[1] == '\xff') {
+ show_msg(MSGERR, "SOCKS V5 server refused authentication methods\n");
+ conn->state = FAILED;
+ return(ECONNREFUSED);
+ }
+
+ /* If the socks server chose username/password authentication */
+ /* (method 2) then do that */
+ if ((unsigned short int) conn->buffer[1] == 2) {
+ show_msg(MSGDEBUG, "SOCKS V5 server chose username/password authentication\n");
+
+ /* Determine the current *nix username */
+ nixuser = getpwuid(getuid());
+
+ if (((uname = conn->path->defuser) == NULL) &&
+ ((uname = getenv("TORSOCKS_USERNAME")) == NULL) &&
+ ((uname = (nixuser == NULL ? NULL : nixuser->pw_name)) == NULL)) {
+ show_msg(MSGERR, "Could not get SOCKS username from "
+ "local passwd file, torsocks.conf "
+ "or $TORSOCKS_USERNAME to authenticate "
+ "with");
+ conn->state = FAILED;
+ return(ECONNREFUSED);
+ }
+
+ if (((upass = getenv("TORSOCKS_PASSWORD")) == NULL) &&
+ ((upass = conn->path->defpass) == NULL)) {
+ show_msg(MSGERR, "Need a password in torsocks.conf or "
+ "$TORSOCKS_PASSWORD to authenticate with");
+ conn->state = FAILED;
+ return(ECONNREFUSED);
+ }
+
+ /* Check that the username / pass specified will */
+ /* fit into the buffer */
+ if ((3 + strlen(uname) + strlen(upass)) >= sizeof(conn->buffer)) {
+ show_msg(MSGERR, "The supplied socks username or "
+ "password is too long");
+ conn->state = FAILED;
+ return(ECONNREFUSED);
+ }
+
+ conn->datalen = 0;
+ conn->buffer[conn->datalen] = '\x01';
+ conn->datalen++;
+ conn->buffer[conn->datalen] = (int8_t) strlen(uname);
+ conn->datalen++;
+ memcpy(&(conn->buffer[conn->datalen]), uname, strlen(uname));
+ conn->datalen = conn->datalen + strlen(uname);
+ conn->buffer[conn->datalen] = (int8_t) strlen(upass);
+ conn->datalen++;
+ memcpy(&(conn->buffer[conn->datalen]), upass, strlen(upass));
+ conn->datalen = conn->datalen + strlen(upass);
+
+ conn->state = SENDING;
+ conn->nextstate = SENTV5AUTH;
+ conn->datadone = 0;
+ } else
+ return(send_socksv5_connect(conn));
+
+ return(0);
+}
+
+static int read_socksv5_auth(struct connreq *conn)
+{
+
+ if (conn->buffer[1] != '\x00') {
+ show_msg(MSGERR, "SOCKS authentication failed, check username and password\n");
+ conn->state = FAILED;
+ return(ECONNREFUSED);
+ }
+
+ /* Ok, we authenticated ok, send the connection request */
+ return(send_socksv5_connect(conn));
+}
+
+static int read_socksv5_connect(struct connreq *conn)
+{
+
+ /* See if the connection succeeded */
+ if (conn->buffer[1] != '\x00') {
+ show_msg(MSGERR, "SOCKS V5 connect failed: ");
+ conn->state = FAILED;
+ switch ((int8_t) conn->buffer[1]) {
+ case 1:
+ show_msg(MSGERR, "General SOCKS server failure\n");
+ return(ECONNABORTED);
+ case 2:
+ show_msg(MSGERR, "Connection denied by rule\n");
+ return(ECONNABORTED);
+ case 3:
+ show_msg(MSGERR, "Network unreachable\n");
+ return(ENETUNREACH);
+ case 4:
+ show_msg(MSGERR, "Host unreachable\n");
+ return(EHOSTUNREACH);
+ case 5:
+ show_msg(MSGERR, "Connection refused\n");
+ return(ECONNREFUSED);
+ case 6:
+ show_msg(MSGERR, "TTL Expired\n");
+ return(ETIMEDOUT);
+ case 7:
+ show_msg(MSGERR, "Command not supported\n");
+ return(ECONNABORTED);
+ case 8:
+ show_msg(MSGERR, "Address type not supported\n");
+ return(ECONNABORTED);
+ default:
+ show_msg(MSGERR, "Unknown error\n");
+ return(ECONNABORTED);
+ }
+ }
+ conn->state = DONE;
+
+ return(0);
+}
+
+static int read_socksv4_req(struct connreq *conn)
+{
+ struct sockrep *thisrep;
+
+ thisrep = (struct sockrep *) conn->buffer;
+
+ if (thisrep->result != 90) {
+ show_msg(MSGERR, "SOCKS V4 connect rejected:\n");
+ conn->state = FAILED;
+ switch(thisrep->result) {
+ case 91:
+ show_msg(MSGERR, "SOCKS server refused connection\n");
+ return(ECONNREFUSED);
+ case 92:
+ show_msg(MSGERR, "SOCKS server refused connection "
+ "because of failed connect to identd "
+ "on this machine\n");
+ return(ECONNREFUSED);
+ case 93:
+ show_msg(MSGERR, "SOCKS server refused connection "
+ "because identd and this library "
+ "reported different user-ids\n");
+ return(ECONNREFUSED);
+ default:
+ show_msg(MSGERR, "Unknown reason\n");
+ return(ECONNREFUSED);
+ }
+ }
+ conn->state = DONE;
+
+ return(0);
+}
+
+#ifdef SUPPORT_RES_API
+int res_init(void)
+{
+ int rc;
+
+ if (!realres_init && ((realres_init = dlsym(RTLD_NEXT, "res_init")) == NULL))
+ LOAD_ERROR("res_init", MSGERR);
+
+ show_msg(MSGDEBUG, "Got res_init request\n");
+
+ /* See comment in close() */
+ if (!tsocks_init_complete)
+ tsocks_init();
+
+ 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 && ((original_res_query = dlsym(RTLD_NEXT, "res_query")) == NULL))
+ LOAD_ERROR("res_query", MSGERR);
+
+ show_msg(MSGDEBUG, "Got res_query request\n");
+
+ /* See comment in close() */
+ if (!tsocks_init_complete)
+ tsocks_init();
+
+ 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 &&
+ ((original_res_querydomain = dlsym(RTLD_NEXT, "res_querydomain")) == NULL))
+ LOAD_ERROR("res_querydoimain", MSGERR);
+
+ show_msg(MSGDEBUG, "Got res_querydomain request\n");
+
+ /* See comment in close() */
+ if (!tsocks_init_complete)
+ tsocks_init();
+
+ 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 &&
+ ((original_res_search = dlsym(RTLD_NEXT, "res_search")) == NULL))
+ LOAD_ERROR("res_search", MSGERR);
+
+ show_msg(MSGDEBUG, "Got res_search request\n");
+
+ /* See comment in close() */
+ if (!tsocks_init_complete)
+ tsocks_init();
+
+ 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 && ((original_res_send = dlsym(RTLD_NEXT, "res_send")) == NULL))
+ LOAD_ERROR("res_send", MSGERR);
+
+ show_msg(MSGDEBUG, "Got res_send request\n");
+
+ /* See comment in close() */
+ if (!tsocks_init_complete)
+ tsocks_init();
+
+ 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 *tsocks_gethostbyname_guts(GETHOSTBYNAME_SIGNATURE, struct hostent *(*original_gethostbyname)(GETHOSTBYNAME_SIGNATURE))
+{
+ if (pool)
+ return our_gethostbyname(pool, name);
+ return original_gethostbyname(name);
+}
+
+struct hostent *tsocks_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 tsocks_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 *tsocks_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 tsocks_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;
+
+ /* See comment in close() */
+ if (!tsocks_init_complete)
+ tsocks_init();
+
+ /* 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(MSGDEBUG, "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 tsocks_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;
+
+ /* See comment in close() */
+ if (!tsocks_init_complete)
+ tsocks_init();
+
+ /* 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(MSGDEBUG, "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/tsocks.c b/src/tsocks.c
deleted file mode 100644
index a227469..0000000
--- a/src/tsocks.c
+++ /dev/null
@@ -1,1757 +0,0 @@
-/***************************************************************************
- * *
- * $Id: tsocks.c,v 1.5 2008-07-06 15:17:35 hoganrobert Exp $ *
- * *
- * Copyright (C) 2008 by Robert Hogan *
- * robert(a)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 tsocks project. *
- * Original copyright notice from tsocks source file follows: *
- * *
- ***************************************************************************/
-/*
-
- TSOCKS - Wrapper library for transparent SOCKS
-
- Copyright (C) 2000 Shaun Clowes
-
- 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., 675 Mass Ave, Cambridge, MA 02139, 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 <common.h>
-#include <pthread.h>
-#include <stdarg.h>
-#if !defined(__APPLE__) && !defined(__darwin__)
-#include <sys/socket.h>
-#endif
-#include <resolv.h>
-#include <parser.h>
-#include <tsocks.h>
-#include "dead_pool.h"
-
-/* Some function names are macroized on Darwin. Allow those names
- to expand accordingly. */
-#define EXPAND_GUTS(x) tsocks_##x##_guts
-#define EXPAND_GUTS_NAME(x) EXPAND_GUTS(x)
-
-/* Global Declarations */
-static dead_pool *pool = NULL;
-
-/* Function prototypes for original functions that we patch */
-#ifdef SUPPORT_RES_API
-int (*realres_init)(void);
-#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 struct connreq *requests = NULL;
-static int suid = 0;
-static char *conffile = NULL;
-static volatile int tsocks_init_complete = 0;
-
-/* Exported Function Prototypes */
-void __attribute__ ((constructor)) tsocks_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 tsocks_res_init_guts */
-#define PATCH_TABLE_EXPANSION(e,r,s,n,b,m) r tsocks_##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 connect_server(struct connreq *conn);
-static int send_socks_request(struct connreq *conn);
-static struct connreq *new_socks_request(int sockid, struct sockaddr_in *connaddr,
- struct sockaddr_in *serveraddr,
- struct serverent *path);
-static void kill_socks_request(struct connreq *conn);
-static int handle_request(struct connreq *conn);
-static struct connreq *find_socks_request(int sockid, int includefailed);
-static int connect_server(struct connreq *conn);
-static int send_socks_request(struct connreq *conn);
-static int send_socksv4_request(struct connreq *conn);
-static int send_socksv5_method(struct connreq *conn);
-static int send_socksv5_connect(struct connreq *conn);
-static int send_buffer(struct connreq *conn);
-static int recv_buffer(struct connreq *conn);
-static int read_socksv5_method(struct connreq *conn);
-static int read_socksv4_req(struct connreq *conn);
-static int read_socksv5_connect(struct connreq *conn);
-static int read_socksv5_auth(struct connreq *conn);
-static int deadpool_init(void);
-static int send_socksv4a_request(struct connreq *conn, const char *onion_host);
-
-static pthread_mutex_t tsocks_init_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-void tsocks_init(void)
-{
-#define LOAD_ERROR(s,l) { \
- char *error; \
- error = dlerror(); \
- show_msg(l, "The symbol %s() was not found in any shared " \
- "library. The error reported was: %s!\n", s, \
- (error)?error:"not found"); \
- dlerror(); \
- }
- pthread_mutex_lock(&tsocks_init_mutex);
-
- /* We only need to be called once */
- if (tsocks_init_complete)
- return;
-
- /* Not strictly true yet, but prevents us getting called while still in progress.*/
- /* This has been observed on Snow Leopard for instance. */
- tsocks_init_complete = 1;
-
- show_msg(MSGWARN, "In tsocks_init \n");
-
- get_environment();
- get_config();
-
- show_msg(MSGWARN, "In tsocks_init after env/config\n");
-
-#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
- if ((realres_init = dlsym(RTLD_NEXT, "res_init")) == NULL)
- LOAD_ERROR("res_init", MSGERR);
- #endif
- #define PATCH_TABLE_EXPANSION(e,r,s,n,b,m) if ((real##n = dlsym(RTLD_NEXT, m)) == NULL) LOAD_ERROR(m, MSG##e);
- #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);
- }
-
- tsocks_init_complete=1;
- pthread_mutex_unlock(&tsocks_init_mutex);
-
- show_msg(MSGWARN, "Exit tsocks_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, 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 tsocks_res_init_guts */
-#define PATCH_TABLE_EXPANSION(e,r,s,n,b,m) \
- r n(s##SIGNATURE) { \
- if (!real##n) { \
- dlerror(); \
- if ((real##n = dlsym(RTLD_NEXT, m)) == NULL) \
- LOAD_ERROR(m, MSG##e); \
- } \
- return tsocks_##b##_guts(s##ARGNAMES, real##n); \
- }
-#include "expansion_table.h"
-#undef PATCH_TABLE_EXPANSION
-
-int tsocks_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;
-
- /* See comment in close() */
- if (!tsocks_init_complete)
- tsocks_init();
-
- /* 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(MSGDEBUG, "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 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 "
- "tsocks 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, HOSTNAMES)) == -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;
- return((rc ? -1 : 0));
- }
-}
-
-int tsocks_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));
- }
-
- if (!tsocks_init_complete)
- tsocks_init();
-
- 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 tsocks_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));
-
- if (!tsocks_init_complete)
- tsocks_init();
-
- 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 tsocks_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 we are called before this symbol has been dlopened then try
- loading symbols now. This is a workaround for a problem I don't
- really understand and have only encountered when using torsocks
- with svn on Fedora 10, so definitely a hack. */
- if (!tsocks_init_complete)
- tsocks_init();
-
- if (original_close == NULL) {
- show_msg(MSGERR, "Unresolved symbol: close\n");
- return(-1);
- }
-
- 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 tsocks_getpeername_guts(GETPEERNAME_SIGNATURE,
- int (*original_getpeername)(GETPEERNAME_SIGNATURE))
-{
- struct connreq *conn;
- int rc;
-
- /* See comment in close() */
- if (!tsocks_init_complete)
- tsocks_init();
-
- if (original_getpeername == NULL) {
- show_msg(MSGERR, "Unresolved symbol: getpeername\n");
- return(-1);
- }
-
- 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;
-}
-
-static struct connreq *new_socks_request(int sockid, struct sockaddr_in *connaddr,
- struct sockaddr_in *serveraddr,
- struct serverent *path)
-{
- struct connreq *newconn;
-
- if ((newconn = malloc(sizeof(*newconn))) == NULL) {
- /* Could not malloc, we're stuffed */
- show_msg(MSGERR, "Could not allocate memory for new socks request\n");
- return(NULL);
- }
-
- /* Add this connection to be proxied to the list */
- memset(newconn, 0x0, sizeof(*newconn));
- newconn->sockid = sockid;
- newconn->state = UNSTARTED;
- newconn->path = path;
- memcpy(&(newconn->connaddr), connaddr, sizeof(newconn->connaddr));
- memcpy(&(newconn->serveraddr), serveraddr, sizeof(newconn->serveraddr));
- newconn->next = requests;
- requests = newconn;
-
- return(newconn);
-}
-
-static void kill_socks_request(struct connreq *conn)
-{
- struct connreq *connnode;
-
- if (requests == conn)
- requests = conn->next;
- else {
- for (connnode = requests; connnode != NULL; connnode = connnode->next) {
- if (connnode->next == conn) {
- connnode->next = conn->next;
- break;
- }
- }
- }
-
- free(conn);
-}
-
-static struct connreq *find_socks_request(int sockid, int includefinished)
-{
- struct connreq *connnode;
-
- for (connnode = requests; connnode != NULL; connnode = connnode->next) {
- if (connnode->sockid == sockid) {
- if (((connnode->state == FAILED) || (connnode->state == DONE)) &&
- !includefinished)
- break;
- else
- return(connnode);
- }
- }
-
- return(NULL);
-}
-
-static int handle_request(struct connreq *conn)
-{
- int rc = 0;
- int i = 0;
-
- show_msg(MSGDEBUG, "Beginning handle loop for socket %d\n", conn->sockid);
-
- while ((rc == 0) &&
- (conn->state != FAILED) &&
- (conn->state != DONE) &&
- (i++ < 20)) {
- show_msg(MSGDEBUG, "In request handle loop for socket %d, "
- "current state of request is %d\n", conn->sockid,
- conn->state);
- switch(conn->state) {
- case UNSTARTED:
- case CONNECTING:
- rc = connect_server(conn);
- break;
- case CONNECTED:
- rc = send_socks_request(conn);
- break;
- case SENDING:
- rc = send_buffer(conn);
- break;
- case RECEIVING:
- rc = recv_buffer(conn);
- break;
- case SENTV4REQ:
- show_msg(MSGDEBUG, "Receiving reply to SOCKS V4 connect request\n");
- conn->datalen = sizeof(struct sockrep);
- conn->datadone = 0;
- conn->state = RECEIVING;
- conn->nextstate = GOTV4REQ;
- break;
- case GOTV4REQ:
- rc = read_socksv4_req(conn);
- break;
- case SENTV5METHOD:
- show_msg(MSGDEBUG, "Receiving reply to SOCKS V5 method negotiation\n");
- conn->datalen = 2;
- conn->datadone = 0;
- conn->state = RECEIVING;
- conn->nextstate = GOTV5METHOD;
- break;
- case GOTV5METHOD:
- rc = read_socksv5_method(conn);
- break;
- case SENTV5AUTH:
- show_msg(MSGDEBUG, "Receiving reply to SOCKS V5 authentication negotiation\n");
- conn->datalen = 2;
- conn->datadone = 0;
- conn->state = RECEIVING;
- conn->nextstate = GOTV5AUTH;
- break;
- case GOTV5AUTH:
- rc = read_socksv5_auth(conn);
- break;
- case SENTV5CONNECT:
- show_msg(MSGDEBUG, "Receiving reply to SOCKS V5 connect request\n");
- conn->datalen = 10;
- conn->datadone = 0;
- conn->state = RECEIVING;
- conn->nextstate = GOTV5CONNECT;
- break;
- case GOTV5CONNECT:
- rc = read_socksv5_connect(conn);
- break;
- }
- conn->err = errno;
- }
-
- if (i == 20)
- show_msg(MSGERR, "Ooops, state loop while handling request %d\n",
- conn->sockid);
-
- show_msg(MSGDEBUG, "Handle loop completed for socket %d in state %d, "
- "returning %d\n", conn->sockid, conn->state, rc);
- return(rc);
-}
-
-static int connect_server(struct connreq *conn)
-{
- int rc;
-
- /* Connect this socket to the socks server */
- show_msg(MSGDEBUG, "Connecting to %s port %d\n",
- inet_ntoa(conn->serveraddr.sin_addr), ntohs(conn->serveraddr.sin_port));
-
- rc = realconnect(conn->sockid, (CONNECT_SOCKARG) &(conn->serveraddr),
- sizeof(conn->serveraddr));
-
- show_msg(MSGDEBUG, "Connect returned %d, errno is %d\n", rc, errno);
- if (rc && errno == EISCONN) {
- rc = 0;
- show_msg(MSGDEBUG, "Socket %d already connected to SOCKS server\n", conn->sockid);
- conn->state = CONNECTED;
- } else if (rc) {
- if (errno != EINPROGRESS) {
- show_msg(MSGERR, "Error %d attempting to connect to SOCKS "
- "server (%s)\n", errno, strerror(errno));
- conn->state = FAILED;
- } else {
- show_msg(MSGDEBUG, "Connection in progress\n");
- conn->state = CONNECTING;
- }
- } else {
- show_msg(MSGDEBUG, "Socket %d connected to SOCKS server\n", conn->sockid);
- conn->state = CONNECTED;
- }
-
- return((rc ? errno : 0));
-}
-
-static int send_socks_request(struct connreq *conn)
-{
- int rc = 0;
-
- if (conn->path->type == 4) {
- char *name = get_pool_entry(pool, &(conn->connaddr.sin_addr));
- if(name != NULL)
- rc = send_socksv4a_request(conn,name);
- else
- rc = send_socksv4_request(conn);
- } else
- rc = send_socksv5_method(conn);
- return(rc);
-}
-
-static int send_socksv4a_request(struct connreq *conn,const char *onion_host)
-{
- struct passwd *user;
- struct sockreq *thisreq;
- int endOfUser;
- /* Determine the current username */
- user = getpwuid(getuid());
-
- thisreq = (struct sockreq *) conn->buffer;
- endOfUser=sizeof(struct sockreq) +
- (user == NULL ? 0 : strlen(user->pw_name)) + 1;
-
- /* Check the buffer has enough space for the request */
- /* and the user name */
- conn->datalen = endOfUser+
- (onion_host == NULL ? 0 : strlen(onion_host)) + 1;
- if (sizeof(conn->buffer) < conn->datalen) {
- show_msg(MSGERR, "The SOCKS username is too long");
- conn->state = FAILED;
- return(ECONNREFUSED);
- }
-
- /* Create the request */
- thisreq->version = 4;
- thisreq->command = 1;
- thisreq->dstport = conn->connaddr.sin_port;
- thisreq->dstip = htonl(1);
-
- /* Copy the username */
- strcpy((char *) thisreq + sizeof(struct sockreq),
- (user == NULL ? "" : user->pw_name));
-
- /* Copy the onion host */
- strcpy((char *) thisreq + endOfUser,
- (onion_host == NULL ? "" : onion_host));
-
- conn->datadone = 0;
- conn->state = SENDING;
- conn->nextstate = SENTV4REQ;
-
- return(0);
-}
-
-static int send_socksv4_request(struct connreq *conn)
-{
- struct passwd *user;
- struct sockreq *thisreq;
-
- /* Determine the current username */
- user = getpwuid(getuid());
-
- thisreq = (struct sockreq *) conn->buffer;
-
- /* Check the buffer has enough space for the request */
- /* and the user name */
- conn->datalen = sizeof(struct sockreq) +
- (user == NULL ? 0 : strlen(user->pw_name)) + 1;
- if (sizeof(conn->buffer) < conn->datalen) {
- show_msg(MSGERR, "The SOCKS username is too long");
- conn->state = FAILED;
- return(ECONNREFUSED);
- }
-
- /* Create the request */
- thisreq->version = 4;
- thisreq->command = 1;
- thisreq->dstport = conn->connaddr.sin_port;
- thisreq->dstip = conn->connaddr.sin_addr.s_addr;
-
- /* Copy the username */
- strcpy((char *) thisreq + sizeof(struct sockreq),
- (user == NULL ? "" : user->pw_name));
-
- conn->datadone = 0;
- conn->state = SENDING;
- conn->nextstate = SENTV4REQ;
-
- return(0);
-}
-
-static int send_socksv5_method(struct connreq *conn)
-{
- char verstring[] = { 0x05, /* Version 5 SOCKS */
- 0x02, /* No. Methods */
- 0x00, /* Null Auth */
- 0x02 }; /* User/Pass Auth */
-
- show_msg(MSGDEBUG, "Constructing V5 method negotiation\n");
- conn->state = SENDING;
- conn->nextstate = SENTV5METHOD;
- memcpy(conn->buffer, verstring, sizeof(verstring));
- conn->datalen = sizeof(verstring);
- conn->datadone = 0;
-
- return(0);
-}
-
-static int send_socksv5_connect(struct connreq *conn)
-{
- int namelen = 0;
- char *name = NULL;
- char constring[] = { 0x05, /* Version 5 SOCKS */
- 0x01, /* Connect request */
- 0x00, /* Reserved */
- 0x01 }; /* IP Version 4 */
-
- show_msg(MSGDEBUG, "Constructing V5 connect request\n");
- conn->datadone = 0;
- conn->state = SENDING;
- conn->nextstate = SENTV5CONNECT;
- memcpy(conn->buffer, constring, sizeof(constring));
- conn->datalen = sizeof(constring);
-
- show_msg(MSGDEBUG, "send_socksv5_connect: looking for: %s\n",
- inet_ntoa(conn->connaddr.sin_addr));
-
- name = get_pool_entry(pool, &(conn->connaddr.sin_addr));
- if(name != NULL) {
- namelen = strlen(name);
- if(namelen > 255) /* "Can't happen" */
- name = NULL;
- }
- if(name != NULL) {
- show_msg(MSGDEBUG, "send_socksv5_connect: found it!\n");
- /* Substitute the domain name from the pool into the SOCKS request. */
- conn->buffer[3] = 0x03; /* Change the ATYP field */
- conn->buffer[4] = namelen; /* Length of name */
- conn->datalen++;
- memcpy(&conn->buffer[conn->datalen], name, namelen);
- conn->datalen += namelen;
- } else {
- show_msg(MSGDEBUG, "send_socksv5_connect: ip address not found\n");
- /* Use the raw IP address */
- memcpy(&conn->buffer[conn->datalen], &(conn->connaddr.sin_addr.s_addr),
- sizeof(conn->connaddr.sin_addr.s_addr));
- conn->datalen += sizeof(conn->connaddr.sin_addr.s_addr);
- }
- memcpy(&conn->buffer[conn->datalen], &(conn->connaddr.sin_port),
- sizeof(conn->connaddr.sin_port));
- conn->datalen += sizeof(conn->connaddr.sin_port);
-
- return(0);
-}
-
-static int send_buffer(struct connreq *conn)
-{
- int rc = 0;
-
- show_msg(MSGDEBUG, "Writing to server (sending %d bytes)\n", conn->datalen);
- while ((rc == 0) && (conn->datadone != conn->datalen)) {
- rc = send(conn->sockid, conn->buffer + conn->datadone,
- conn->datalen - conn->datadone, 0);
- if (rc > 0) {
- conn->datadone += rc;
- rc = 0;
- } else {
- if (errno != EWOULDBLOCK)
- show_msg(MSGDEBUG, "Write failed, %s\n", strerror(errno));
- rc = errno;
- }
- }
-
- if (conn->datadone == conn->datalen)
- conn->state = conn->nextstate;
-
- show_msg(MSGDEBUG, "Sent %d bytes of %d bytes in buffer, return code is %d\n",
- conn->datadone, conn->datalen, rc);
- return(rc);
-}
-
-static int recv_buffer(struct connreq *conn)
-{
- int rc = 0;
-
- show_msg(MSGDEBUG, "Reading from server (expecting %d bytes)\n", conn->datalen);
- while ((rc == 0) && (conn->datadone != conn->datalen)) {
- rc = recv(conn->sockid, conn->buffer + conn->datadone,
- conn->datalen - conn->datadone, 0);
- if (rc > 0) {
- conn->datadone += rc;
- rc = 0;
- } else if (rc == 0) {
- show_msg(MSGDEBUG, "Peer has shutdown but we only read %d of %d bytes.\n",
- conn->datadone, conn->datalen);
- rc = ENOTCONN; /* ENOTCONN seems like the most fitting error message */
- } else {
- if (errno != EWOULDBLOCK)
- show_msg(MSGDEBUG, "Read failed, %s\n", strerror(errno));
- rc = errno;
- }
- }
-
- if (conn->datadone == conn->datalen)
- conn->state = conn->nextstate;
-
- show_msg(MSGDEBUG, "Received %d bytes of %d bytes expected, return code is %d\n",
- conn->datadone, conn->datalen, rc);
- return(rc);
-}
-
-static int read_socksv5_method(struct connreq *conn)
-{
- struct passwd *nixuser;
- char *uname, *upass;
-
- /* See if we offered an acceptable method */
- if (conn->buffer[1] == '\xff') {
- show_msg(MSGERR, "SOCKS V5 server refused authentication methods\n");
- conn->state = FAILED;
- return(ECONNREFUSED);
- }
-
- /* If the socks server chose username/password authentication */
- /* (method 2) then do that */
- if ((unsigned short int) conn->buffer[1] == 2) {
- show_msg(MSGDEBUG, "SOCKS V5 server chose username/password authentication\n");
-
- /* Determine the current *nix username */
- nixuser = getpwuid(getuid());
-
- if (((uname = conn->path->defuser) == NULL) &&
- ((uname = getenv("TORSOCKS_USERNAME")) == NULL) &&
- ((uname = (nixuser == NULL ? NULL : nixuser->pw_name)) == NULL)) {
- show_msg(MSGERR, "Could not get SOCKS username from "
- "local passwd file, torsocks.conf "
- "or $TORSOCKS_USERNAME to authenticate "
- "with");
- conn->state = FAILED;
- return(ECONNREFUSED);
- }
-
- if (((upass = getenv("TORSOCKS_PASSWORD")) == NULL) &&
- ((upass = conn->path->defpass) == NULL)) {
- show_msg(MSGERR, "Need a password in torsocks.conf or "
- "$TORSOCKS_PASSWORD to authenticate with");
- conn->state = FAILED;
- return(ECONNREFUSED);
- }
-
- /* Check that the username / pass specified will */
- /* fit into the buffer */
- if ((3 + strlen(uname) + strlen(upass)) >= sizeof(conn->buffer)) {
- show_msg(MSGERR, "The supplied socks username or "
- "password is too long");
- conn->state = FAILED;
- return(ECONNREFUSED);
- }
-
- conn->datalen = 0;
- conn->buffer[conn->datalen] = '\x01';
- conn->datalen++;
- conn->buffer[conn->datalen] = (int8_t) strlen(uname);
- conn->datalen++;
- memcpy(&(conn->buffer[conn->datalen]), uname, strlen(uname));
- conn->datalen = conn->datalen + strlen(uname);
- conn->buffer[conn->datalen] = (int8_t) strlen(upass);
- conn->datalen++;
- memcpy(&(conn->buffer[conn->datalen]), upass, strlen(upass));
- conn->datalen = conn->datalen + strlen(upass);
-
- conn->state = SENDING;
- conn->nextstate = SENTV5AUTH;
- conn->datadone = 0;
- } else
- return(send_socksv5_connect(conn));
-
- return(0);
-}
-
-static int read_socksv5_auth(struct connreq *conn)
-{
-
- if (conn->buffer[1] != '\x00') {
- show_msg(MSGERR, "SOCKS authentication failed, check username and password\n");
- conn->state = FAILED;
- return(ECONNREFUSED);
- }
-
- /* Ok, we authenticated ok, send the connection request */
- return(send_socksv5_connect(conn));
-}
-
-static int read_socksv5_connect(struct connreq *conn)
-{
-
- /* See if the connection succeeded */
- if (conn->buffer[1] != '\x00') {
- show_msg(MSGERR, "SOCKS V5 connect failed: ");
- conn->state = FAILED;
- switch ((int8_t) conn->buffer[1]) {
- case 1:
- show_msg(MSGERR, "General SOCKS server failure\n");
- return(ECONNABORTED);
- case 2:
- show_msg(MSGERR, "Connection denied by rule\n");
- return(ECONNABORTED);
- case 3:
- show_msg(MSGERR, "Network unreachable\n");
- return(ENETUNREACH);
- case 4:
- show_msg(MSGERR, "Host unreachable\n");
- return(EHOSTUNREACH);
- case 5:
- show_msg(MSGERR, "Connection refused\n");
- return(ECONNREFUSED);
- case 6:
- show_msg(MSGERR, "TTL Expired\n");
- return(ETIMEDOUT);
- case 7:
- show_msg(MSGERR, "Command not supported\n");
- return(ECONNABORTED);
- case 8:
- show_msg(MSGERR, "Address type not supported\n");
- return(ECONNABORTED);
- default:
- show_msg(MSGERR, "Unknown error\n");
- return(ECONNABORTED);
- }
- }
- conn->state = DONE;
-
- return(0);
-}
-
-static int read_socksv4_req(struct connreq *conn)
-{
- struct sockrep *thisrep;
-
- thisrep = (struct sockrep *) conn->buffer;
-
- if (thisrep->result != 90) {
- show_msg(MSGERR, "SOCKS V4 connect rejected:\n");
- conn->state = FAILED;
- switch(thisrep->result) {
- case 91:
- show_msg(MSGERR, "SOCKS server refused connection\n");
- return(ECONNREFUSED);
- case 92:
- show_msg(MSGERR, "SOCKS server refused connection "
- "because of failed connect to identd "
- "on this machine\n");
- return(ECONNREFUSED);
- case 93:
- show_msg(MSGERR, "SOCKS server refused connection "
- "because identd and this library "
- "reported different user-ids\n");
- return(ECONNREFUSED);
- default:
- show_msg(MSGERR, "Unknown reason\n");
- return(ECONNREFUSED);
- }
- }
- conn->state = DONE;
-
- return(0);
-}
-
-#ifdef SUPPORT_RES_API
-int res_init(void)
-{
- int rc;
-
- if (!realres_init && ((realres_init = dlsym(RTLD_NEXT, "res_init")) == NULL))
- LOAD_ERROR("res_init", MSGERR);
-
- show_msg(MSGDEBUG, "Got res_init request\n");
-
- /* See comment in close() */
- if (!tsocks_init_complete)
- tsocks_init();
-
- 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 && ((original_res_query = dlsym(RTLD_NEXT, "res_query")) == NULL))
- LOAD_ERROR("res_query", MSGERR);
-
- show_msg(MSGDEBUG, "Got res_query request\n");
-
- /* See comment in close() */
- if (!tsocks_init_complete)
- tsocks_init();
-
- 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 &&
- ((original_res_querydomain = dlsym(RTLD_NEXT, "res_querydomain")) == NULL))
- LOAD_ERROR("res_querydoimain", MSGERR);
-
- show_msg(MSGDEBUG, "Got res_querydomain request\n");
-
- /* See comment in close() */
- if (!tsocks_init_complete)
- tsocks_init();
-
- 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 &&
- ((original_res_search = dlsym(RTLD_NEXT, "res_search")) == NULL))
- LOAD_ERROR("res_search", MSGERR);
-
- show_msg(MSGDEBUG, "Got res_search request\n");
-
- /* See comment in close() */
- if (!tsocks_init_complete)
- tsocks_init();
-
- 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 && ((original_res_send = dlsym(RTLD_NEXT, "res_send")) == NULL))
- LOAD_ERROR("res_send", MSGERR);
-
- show_msg(MSGDEBUG, "Got res_send request\n");
-
- /* See comment in close() */
- if (!tsocks_init_complete)
- tsocks_init();
-
- 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 *tsocks_gethostbyname_guts(GETHOSTBYNAME_SIGNATURE, struct hostent *(*original_gethostbyname)(GETHOSTBYNAME_SIGNATURE))
-{
- if (pool)
- return our_gethostbyname(pool, name);
- return original_gethostbyname(name);
-}
-
-struct hostent *tsocks_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 tsocks_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 *tsocks_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 tsocks_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;
-
- /* See comment in close() */
- if (!tsocks_init_complete)
- tsocks_init();
-
- /* 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(MSGDEBUG, "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 tsocks_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;
-
- /* See comment in close() */
- if (!tsocks_init_complete)
- tsocks_init();
-
- /* 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(MSGDEBUG, "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);
-}
-
1
0

23 Oct '11
commit 7079fb3523ce72fdca18e87bc430fa7955d97063
Author: Robert Hogan <robert(a)roberthogan.net>
Date: Sun Sep 19 13:41:54 2010 +0100
Only enable debug output for debug builds
Debug output was printing on release builds and getting suppressed
on debug builds - which is the wrong way round!
---
configure.in | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/configure.in b/configure.in
index 06461ff..ee5b4f4 100644
--- a/configure.in
+++ b/configure.in
@@ -200,7 +200,7 @@ if test "${enable_oldmethod}" = "yes"; then
oldmethod="yes"
fi
-if test "x${enable_debug}" = "x"; then
+if test "x${enable_debug}" != "x"; then
AC_DEFINE([ALLOW_MSG_OUTPUT],[],[Description])
fi
1
0