├── .gitignore ├── .travis.yml ├── ChangeLog ├── INSTALL ├── LICENSE ├── Makefile.am ├── README.md ├── autogen.sh ├── config ├── .placeholder ├── ax_check_compile_flag.m4 └── ax_check_link_flag.m4 ├── configure.ac ├── doc ├── Makefile.am ├── notes │ └── DEBUG ├── proposals │ └── 01-Thread-safe-design.txt ├── socks │ ├── SOCKS5 │ └── socks-extensions.txt ├── torsocks.1 ├── torsocks.8 ├── torsocks.conf └── torsocks.conf.5 ├── extras ├── Makefile.am ├── torsocks-bash_completion └── torsocks-zsh_completion ├── gpl-2.0.txt ├── include └── .placeholder ├── src ├── Makefile.am ├── bin │ ├── Makefile.am │ └── torsocks.in ├── common │ ├── Makefile.am │ ├── compat.c │ ├── compat.h │ ├── config-file.c │ ├── config-file.h │ ├── connection.c │ ├── connection.h │ ├── defaults.h │ ├── ht.h │ ├── log.c │ ├── log.h │ ├── macros.h │ ├── onion.c │ ├── onion.h │ ├── ref.h │ ├── socks5.c │ ├── socks5.h │ ├── utils.c │ └── utils.h └── lib │ ├── Makefile.am │ ├── accept.c │ ├── close.c │ ├── connect.c │ ├── execve.c │ ├── exit.c │ ├── fclose.c │ ├── getaddrinfo.c │ ├── gethostbyname.c │ ├── getpeername.c │ ├── listen.c │ ├── recv.c │ ├── sendto.c │ ├── socket.c │ ├── socketpair.c │ ├── syscall.c │ ├── torsocks.c │ └── torsocks.h └── tests ├── Makefile.am ├── helpers.c ├── helpers.h ├── tap-driver.sh ├── test_connect.c ├── test_dns.c ├── test_fd_passing.c ├── test_getpeername.c ├── test_socket.c ├── unit ├── Makefile.am ├── fixtures │ ├── config0 │ ├── config1 │ ├── config2 │ ├── config3 │ ├── config4 │ ├── config5 │ ├── config6 │ ├── config7 │ ├── config8 │ ├── config9_32 │ └── config9_64 ├── test_compat.c ├── test_config-file.c ├── test_connection.c ├── test_onion.c ├── test_socks5.c └── test_utils.c └── utils ├── Makefile.am ├── fixtures.h └── tap ├── Makefile.am ├── tap.c ├── tap.h └── tap.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | *.swp 4 | *.o 5 | *.swo 6 | *.pyc 7 | Makefile 8 | .libs/ 9 | .deps/ 10 | *~ 11 | *.la 12 | *.lo 13 | Makefile.in 14 | *.loT 15 | *.info 16 | *.bz2 17 | *.xz 18 | *.tar 19 | aclocal.m4 20 | autom4te.cache/ 21 | config.guess 22 | config.h 23 | config.h.in 24 | config.log 25 | config.status 26 | config.sub 27 | configure 28 | depcomp 29 | install-sh 30 | libtool 31 | ltmain.sh 32 | missing 33 | stamp-h1 34 | tags 35 | cscope.* 36 | 37 | config/ 38 | !config/ax_check_compile_flag.m4 39 | !config/ax_check_link_flag .m4 40 | 41 | doc/torsocks.1 42 | doc/torsocks.8 43 | doc/torsocks.conf.5 44 | doc/usewithtor.1 45 | 46 | src/bin/torsocks 47 | 48 | tests/test_connect 49 | tests/test_dns 50 | tests/test_socket 51 | tests/test_fd_passing 52 | tests/test_getpeername 53 | tests/unit/test_onion 54 | tests/unit/test_connection 55 | tests/unit/test_utils 56 | tests/unit/test_config-file 57 | tests/unit/test_socks5 58 | tests/unit/test_compat 59 | 60 | tests/*.log 61 | tests/*.trs 62 | tests/unit/*.log 63 | tests/unit/*.trs 64 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | before_script: ./autogen.sh 3 | compiler: 4 | - clang 5 | - gcc 6 | branches: 7 | only: 8 | - master 9 | before_install: 10 | - sudo apt-get update -qq 11 | - sudo apt-get install -qq autotools-dev pkg-config hardening-wrapper automake autoconf libtool 12 | script: ./configure && make 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Torsocks licensing 2 | David Goulet 3 | August 11th, 2014 4 | 5 | * GPLv2 6 | 7 | The entire code is distributed under the GPLv2 license. See gpl-2.0.txt for 8 | more details. 9 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I config 2 | 3 | SUBDIRS = src doc tests extras 4 | 5 | dist_doc_DATA = ChangeLog 6 | 7 | EXTRA_DIST = gpl-2.0.txt extras/torsocks-bash_completion 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/dgoulet/torsocks.png)](https://travis-ci.org/dgoulet/torsocks) 2 | 3 | What is torsocks? 4 | ----------------- 5 | 6 | Torsocks allows you to use most applications in a safe way with Tor. It ensures 7 | that DNS requests are handled safely and explicitly rejects any traffic other 8 | than TCP from the application you're using. 9 | 10 | Torsocks is an ELF shared library that is loaded before all others. The 11 | library overrides every needed Internet communication libc function calls such 12 | as connect(2) or gethostbyname(3). 13 | 14 | BE ADVISE: It uses the LD\_PRELOAD mechanism (man ld.so.8) which means that if 15 | the application is not using the libc or for instance uses raw syscalls, 16 | torsocks will be useless and the traffic will not go through Tor. 17 | 18 | This process is transparent to the user and if torsocks detects any 19 | communication that can't go through the Tor network such as UDP traffic, for 20 | instance, the connection is denied. If, for any reason, there is no way for 21 | torsocks to provide the Tor anonymity guarantee to your application, torsocks 22 | will force the application to quit and stop everything. 23 | 24 | Requirements 25 | ----------------- 26 | 27 | - autoconf 28 | - automake 29 | - libtool 30 | - gcc 31 | 32 | Installation 33 | ----------------- 34 | 35 | $ ./autogen.sh 36 | $ ./configure 37 | $ make 38 | $ sudo make install 39 | 40 | If you are compiling it from the git repository, run ./autogen.sh before the 41 | configure script. 42 | 43 | Using torsocks 44 | -------------- 45 | 46 | Once you have installed torsocks, just launch it like so: 47 | 48 | $ torsocks [application] 49 | 50 | So, for example you can use ssh to a some.ssh.com by doing: 51 | 52 | $ torsocks ssh username@some.ssh.com 53 | 54 | You can use the torsocks library without the script provided: 55 | 56 | $ LD_PRELOAD=/full/path/to/libtorsocks.so your_app 57 | 58 | For more details, please see the torsocks.1, torsocks.8 and torsocks.conf.5 man 59 | pages. Also, you can use -h, --help for all the possible options of the 60 | torsocks script. 61 | 62 | A configuration file named *torsocks.conf* is also provided for the user to 63 | control some parameters. 64 | 65 | More informations 66 | -------------- 67 | 68 | torsocks is distributed under the GNU General Public License version 2. 69 | 70 | Mailing list for help is and for development 71 | use . You can find the project also on IRC server 72 | irc.oftc.net (OFTC) in #tor and #tor-dev. 73 | 74 | See more information about the Tor project at https://www.torproject.org. 75 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -x 4 | 5 | if [ ! -e config ]; then 6 | mkdir config 7 | fi 8 | 9 | autoreconf -i 10 | -------------------------------------------------------------------------------- /config/.placeholder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dgoulet/torsocks/d4b0a84bdf2a1895c8ec3091dc2767fd9f8c2d66/config/.placeholder -------------------------------------------------------------------------------- /config/ax_check_compile_flag.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # Check whether the given FLAG works with the current language's compiler 12 | # or gives an error. (Warnings, however, are ignored) 13 | # 14 | # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on 15 | # success/failure. 16 | # 17 | # If EXTRA-FLAGS is defined, it is added to the current language's default 18 | # flags (e.g. CFLAGS) when the check is done. The check is thus made with 19 | # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to 20 | # force the compiler to issue an error when a bad flag is given. 21 | # 22 | # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this 23 | # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. 24 | # 25 | # LICENSE 26 | # 27 | # Copyright (c) 2008 Guido U. Draheim 28 | # Copyright (c) 2011 Maarten Bosmans 29 | # 30 | # This program is free software: you can redistribute it and/or modify it 31 | # under the terms of the GNU General Public License as published by the 32 | # Free Software Foundation, either version 3 of the License, or (at your 33 | # option) any later version. 34 | # 35 | # This program is distributed in the hope that it will be useful, but 36 | # WITHOUT ANY WARRANTY; without even the implied warranty of 37 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 38 | # Public License for more details. 39 | # 40 | # You should have received a copy of the GNU General Public License along 41 | # with this program. If not, see . 42 | # 43 | # As a special exception, the respective Autoconf Macro's copyright owner 44 | # gives unlimited permission to copy, distribute and modify the configure 45 | # scripts that are the output of Autoconf when processing the Macro. You 46 | # need not follow the terms of the GNU General Public License when using 47 | # or distributing such scripts, even though portions of the text of the 48 | # Macro appear in them. The GNU General Public License (GPL) does govern 49 | # all other use of the material that constitutes the Autoconf Macro. 50 | # 51 | # This special exception to the GPL applies to versions of the Autoconf 52 | # Macro released by the Autoconf Archive. When you make and distribute a 53 | # modified version of the Autoconf Macro, you may extend this special 54 | # exception to the GPL to apply to your modified version as well. 55 | 56 | #serial 2 57 | 58 | AC_DEFUN([AX_CHECK_COMPILE_FLAG], 59 | [AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX 60 | AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl 61 | AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ 62 | ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS 63 | _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" 64 | AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], 65 | [AS_VAR_SET(CACHEVAR,[yes])], 66 | [AS_VAR_SET(CACHEVAR,[no])]) 67 | _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) 68 | AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], 69 | [m4_default([$2], :)], 70 | [m4_default([$3], :)]) 71 | AS_VAR_POPDEF([CACHEVAR])dnl 72 | ])dnl AX_CHECK_COMPILE_FLAGS 73 | -------------------------------------------------------------------------------- /config/ax_check_link_flag.m4: -------------------------------------------------------------------------------- 1 | # =========================================================================== 2 | # http://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html 3 | # =========================================================================== 4 | # 5 | # SYNOPSIS 6 | # 7 | # AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS]) 8 | # 9 | # DESCRIPTION 10 | # 11 | # Check whether the given FLAG works with the linker or gives an error. 12 | # (Warnings, however, are ignored) 13 | # 14 | # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on 15 | # success/failure. 16 | # 17 | # If EXTRA-FLAGS is defined, it is added to the linker's default flags 18 | # when the check is done. The check is thus made with the flags: "LDFLAGS 19 | # EXTRA-FLAGS FLAG". This can for example be used to force the linker to 20 | # issue an error when a bad flag is given. 21 | # 22 | # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this 23 | # macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG. 24 | # 25 | # LICENSE 26 | # 27 | # Copyright (c) 2008 Guido U. Draheim 28 | # Copyright (c) 2011 Maarten Bosmans 29 | # 30 | # This program is free software: you can redistribute it and/or modify it 31 | # under the terms of the GNU General Public License as published by the 32 | # Free Software Foundation, either version 3 of the License, or (at your 33 | # option) any later version. 34 | # 35 | # This program is distributed in the hope that it will be useful, but 36 | # WITHOUT ANY WARRANTY; without even the implied warranty of 37 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 38 | # Public License for more details. 39 | # 40 | # You should have received a copy of the GNU General Public License along 41 | # with this program. If not, see . 42 | # 43 | # As a special exception, the respective Autoconf Macro's copyright owner 44 | # gives unlimited permission to copy, distribute and modify the configure 45 | # scripts that are the output of Autoconf when processing the Macro. You 46 | # need not follow the terms of the GNU General Public License when using 47 | # or distributing such scripts, even though portions of the text of the 48 | # Macro appear in them. The GNU General Public License (GPL) does govern 49 | # all other use of the material that constitutes the Autoconf Macro. 50 | # 51 | # This special exception to the GPL applies to versions of the Autoconf 52 | # Macro released by the Autoconf Archive. When you make and distribute a 53 | # modified version of the Autoconf Macro, you may extend this special 54 | # exception to the GPL to apply to your modified version as well. 55 | 56 | #serial 2 57 | 58 | AC_DEFUN([AX_CHECK_LINK_FLAG], 59 | [AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl 60 | AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [ 61 | ax_check_save_flags=$LDFLAGS 62 | LDFLAGS="$LDFLAGS $4 $1" 63 | AC_LINK_IFELSE([AC_LANG_PROGRAM()], 64 | [AS_VAR_SET(CACHEVAR,[yes])], 65 | [AS_VAR_SET(CACHEVAR,[no])]) 66 | LDFLAGS=$ax_check_save_flags]) 67 | AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], 68 | [m4_default([$2], :)], 69 | [m4_default([$3], :)]) 70 | AS_VAR_POPDEF([CACHEVAR])dnl 71 | ])dnl AX_CHECK_LINK_FLAGS 72 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # 1. Initialize the autoconf build 3 | ############################################################################## 4 | 5 | # Process this file with autoconf to produce a configure script. 6 | AC_INIT([torsocks], [2.3.0],[dgoulet@torproject.org],[],[https://torproject.org]) 7 | AC_CONFIG_AUX_DIR([config]) 8 | AC_CANONICAL_TARGET 9 | # Get hostname and other information. 10 | AC_CANONICAL_HOST 11 | AC_CONFIG_MACRO_DIR([config]) 12 | 13 | # Create a config.h file to store defines generated by configure 14 | AC_CONFIG_HEADER([include/config.h]) 15 | 16 | # Try to enable the POSIX extensions. 17 | AC_USE_SYSTEM_EXTENSIONS 18 | 19 | # Automake initialization 20 | AM_INIT_AUTOMAKE([foreign dist-xz no-dist-gzip]) 21 | 22 | # Silent compilation. Easier to spot errors! 23 | m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) 24 | 25 | dnl Checks for programs. 26 | AC_PROG_CC 27 | AC_PROG_INSTALL 28 | AC_PROG_LN_S 29 | 30 | ############################################################################## 31 | # 2. Check for some standard headers and libraries 32 | ############################################################################## 33 | 34 | dnl Check if the C compiler accepts -Wall 35 | AC_MSG_CHECKING(if the C compiler accepts -Wall) 36 | OLDCFLAGS="$CFLAGS" 37 | CFLAGS="$CFLAGS -Wall" 38 | AC_TRY_COMPILE(,, 39 | [AC_MSG_RESULT(yes)], 40 | [ 41 | CFLAGS="$OLDCFLAGS" 42 | AC_MSG_RESULT(no) 43 | ] 44 | ) 45 | 46 | dnl Checks for standard header files. 47 | AC_HEADER_STDC 48 | 49 | AC_CHECK_HEADERS(dlfcn.h sys/syscall.h sys/socket.h arpa/inet.h \ 50 | assert.h netdb.h errno.h stdarg.h time.h,, 51 | [AC_MSG_ERROR("Required header not found")] 52 | ) 53 | 54 | dnl Checks for required library functions. 55 | AC_CHECK_FUNCS(strcspn strdup strerror strcasecmp strncasecmp mmap munmap \ 56 | socket connect close syscall recv send memset memcpy strlen \ 57 | strncpy strcmp malloc calloc strstr strtoul free,, 58 | [AC_MSG_ERROR("Required function not found")] 59 | ) 60 | 61 | ############################################################################## 62 | # 3. Determine libraries we need to include when linking libtorsocks. 63 | # OpenBSD and OSX have some special requirements here. 64 | # Also check the host we're building on, as some of the code 65 | # in torsocks.c and elsewhere is platform-dependent. 66 | ############################################################################## 67 | 68 | dnl Check for a function to convert an ascii ip address 69 | dnl to a sin_addr. 70 | AC_CHECK_FUNC(inet_aton, AC_DEFINE([HAVE_INET_ATON],[],[Description]), 71 | [AC_CHECK_FUNC(inet_addr, AC_DEFINE([HAVE_INET_ADDR],[],[Description]), 72 | [AC_CHECK_LIB(nsl, inet_addr, 73 | [ 74 | AC_DEFINE([HAVE_INET_ADDR],[],[Description]) 75 | LIBS="${LIBS} -lnsl" 76 | ], 77 | [AC_MSG_ERROR("Neither inet_aton or inet_addr present")] 78 | )] 79 | )] 80 | ) 81 | 82 | dnl Look for gethostbyname (needed by torsocks) 83 | AC_CHECK_FUNC(gethostbyname, AC_DEFINE([HAVE_GETHOSTBYNAME],[],[Description]), 84 | [AC_CHECK_LIB(xnet, gethostbyname, AC_DEFINE([HAVE_GETHOSTBYNAME],[],[Description]), 85 | [AC_MSG_ERROR(["gethostbyname not found, name lookups in torsocks disabled"])] 86 | )] 87 | ) 88 | 89 | dnl Do we have dlopen(3) in libdl? 90 | AC_SEARCH_LIBS([dlopen], [dl],, 91 | [AC_MSG_ERROR("dlopen function not found in libdl")] 92 | ) 93 | 94 | dnl OpenBSD needs -lpthread. It also doesn't support AI_V4MAPPED. 95 | case $host in 96 | *-*-openbsd*) 97 | AC_DEFINE(OPENBSD, 1, "Define to handle OpenBSD") 98 | AC_SEARCH_LIBS(pthread_create, [pthread]) 99 | ;; 100 | *-*-freebsd*) 101 | AC_DEFINE(FREEBSD, 1, "Define to handle FreeBSD") 102 | ;; 103 | *-*-darwin*) 104 | dnl Needed to compile tests. 105 | dnl See https://bugs.g10code.com/gnupg/issue1292: 106 | dnl "On OS X (at least in 10.6 and I believe starting at 10.3) the DNS resolution 107 | dnl services fail to compile. This is a result of the addition of BIND9 compatible 108 | dnl resolution libraries on OS X that are being picked up by the configure script 109 | dnl instead of -lresolv causing the tests for useable resolution services to fail 110 | dnl thus disabling features like pka auto lookup." 111 | LIBS="-lresolv $LIBS" 112 | ;; 113 | esac 114 | 115 | if test "x${enable_envconf}" = "x"; then 116 | AC_DEFINE([ALLOW_ENV_CONFIG],[],[Description]) 117 | fi 118 | 119 | dnl Get libc full system path. Use prefix or some hardcoded standard 120 | dnl location on Unixish system. 121 | AC_MSG_CHECKING(file name of the C library) 122 | AS_CASE([$host_os], 123 | [darwin*], [libc_name="libSystem.dylib"], 124 | [linux*|kfreebsd*-gnu|freebsd*], 125 | [ 126 | libc_name=`ldd /usr/bin/yes | grep 'libc\.' | cut -d ' ' -f 1 | tr -d '\t'` 127 | if test "${libc_name}" == ""; then 128 | # Default libc on most system. 129 | libc_name="libc.so.6" 130 | fi 131 | ], 132 | [libc_name="libc.so"] 133 | ) 134 | AC_DEFINE_UNQUOTED([LIBC_NAME],["${libc_name}"], [Description]) 135 | AC_MSG_RESULT($libc_name) 136 | 137 | ############################################################################## 138 | # 5. Determine how to preload libtorsocks.so on this system. 139 | # On Linux this is with the LD_PRELOAD variable, on OSX 140 | # we need to use DYLD_INSERT_LIBRARIES. 141 | ############################################################################## 142 | 143 | # This variable is used for the LDFLAGS in test/Makefile.am 144 | TESTLDFLAGS="$LDFLAGS" 145 | AC_SUBST(TESTLDFLAGS) 146 | 147 | # Version information for libtorsocks 148 | TORSOCKSLDFLAGS="$LDFLAGS -version-info 1:0:0" 149 | 150 | dnl Linker checks for Mac OSX, which uses DYLD_INSERT_LIBRARIES 151 | dnl instead of LD_PRELOAD 152 | case "$host_os" in 153 | darwin*) 154 | dnl Check if the linker accepts -dynamiclib; necessary on Mac OS X 155 | AC_MSG_CHECKING(if the linker accepts -dynamiclib) 156 | OLDLDFLAGS="$TORSOCKSLDFLAGS" 157 | TORSOCKSLDFLAGS="$TORSOCKSLDFLAGS -dynamiclib" 158 | AC_TRY_COMPILE(,, [AC_MSG_RESULT(yes)], 159 | [ 160 | TORSOCKSLDFLAGS="$OLDLDFLAGS" 161 | AC_MSG_RESULT(no) 162 | ] 163 | ) 164 | 165 | # dnl Check if the linker accepts -multiply_defined suppress; necessary on Mac OS X 166 | # AC_MSG_CHECKING(if the linker accepts -multiply_defined suppress) 167 | # OLDLDFLAGS="$LDFLAGS" 168 | # LDFLAGS="$LDFLAGS -multiply_defined suppress" 169 | # AC_TRY_COMPILE(,,AC_MSG_RESULT(yes),[ 170 | # LDFLAGS="$OLDLDFLAGS" 171 | # AC_MSG_RESULT(no)]) 172 | 173 | dnl Check if the linker accepts -single_module; necessary on Mac OS X 174 | AC_MSG_CHECKING(if the linker accepts -single_module) 175 | OLDLDFLAGS="$TORSOCKSLDFLAGS" 176 | SHLIB_EXT="so" 177 | LDPRELOAD="LD_PRELOAD" 178 | TORSOCKSLDFLAGS="$TORSOCKSLDFLAGS -single_module" 179 | AC_TRY_COMPILE(,, 180 | [ 181 | SHLIB_EXT="dylib" 182 | LDPRELOAD="DYLD_INSERT_LIBRARIES" 183 | AC_MSG_RESULT(yes) 184 | ], 185 | [ 186 | TORSOCKSLDFLAGS="$OLDLDFLAGS" 187 | AC_MSG_RESULT(no) 188 | ] 189 | ) 190 | ;; 191 | *) 192 | SHLIB_EXT="so" 193 | LDPRELOAD="LD_PRELOAD" 194 | ;; 195 | esac 196 | 197 | AC_SUBST(SHLIB_EXT) 198 | AC_SUBST(LDPRELOAD) 199 | AC_SUBST(TORSOCKSLDFLAGS) 200 | 201 | ############################################################################## 202 | # 7. Determine where the install should write the default configuration 203 | # file and where libtorsocks should read it from by default. 204 | ############################################################################## 205 | 206 | if test "x$prefix" = "xNONE"; then 207 | prefix=$ac_default_prefix 208 | fi 209 | 210 | if test "x$CONFDIR" = "x"; then 211 | CONFDIR=`eval echo $sysconfdir` 212 | fi 213 | AC_SUBST(CONFDIR) 214 | AH_TEMPLATE([CONFDIR],[torsocks configuration directory]) 215 | AC_DEFINE_UNQUOTED(CONFDIR,"$CONFDIR") 216 | 217 | AC_ARG_WITH(conf, 218 | [ --with-conf= location of configuration file (${CONFDIR}/torsocks.conf default)],[ 219 | if test "${withval}" = "yes" ; then 220 | AC_MSG_ERROR("--with-conf requires the location of the configuration file as an argument") 221 | else 222 | AC_DEFINE_UNQUOTED([CONF_FILE], ["${withval}"],[Description]) 223 | fi 224 | ], [ 225 | AC_DEFINE_UNQUOTED([CONF_FILE], ["${CONFDIR}/torsocks.conf"],[Description]) 226 | ]) 227 | 228 | ############################################################################## 229 | # 8. Clean up and create some supporting scripts from their *.in files 230 | ############################################################################## 231 | 232 | AC_LANG_C 233 | AC_PROG_CC 234 | AC_LIBTOOL_DLOPEN 235 | AC_PROG_LIBTOOL 236 | AC_SUBST(LIBTOOL_DEPS) 237 | AC_ENABLE_SHARED 238 | AC_ENABLE_STATIC 239 | 240 | DEFAULT_INCLUDES="-I\$(top_srcdir) -I\$(top_builddir) -I\$(top_builddir)/src -I\$(top_builddir)/include -include config.h" 241 | AC_SUBST(DEFAULT_INCLUDES) 242 | 243 | ############################################################################## 244 | # 9. Test and add hardening flags 245 | ############################################################################## 246 | 247 | # Check for the gcc hardening flags. 248 | AX_CHECK_COMPILE_FLAG([-fPIE],[CFLAGS="$CFLAGS -fPIE"],[],[]) 249 | AX_CHECK_COMPILE_FLAG([-fwrapv],[CFLAGS="$CFLAGS -fwrapv"],[],[]) 250 | AX_CHECK_COMPILE_FLAG([--param ssp-buffer-size=1], 251 | [CFLAGS="$CFLAGS --param ssp-buffer-size=1"],[],[]) 252 | AX_CHECK_COMPILE_FLAG([-fstack-protector-all], 253 | [CFLAGS="$CFLAGS -fstack-protector-all"],[],[] 254 | ) 255 | 256 | dnl Add hardening linker flags 257 | AX_CHECK_LINK_FLAG([-pie],[LDFLAGS="$LDFLAGS -pie"],[],[]) 258 | AX_CHECK_LINK_FLAG([-z relro],[LDFLAGS="$LDFLAGS -z relro"],[],[]) 259 | AX_CHECK_LINK_FLAG([-z now],[LDFLAGS="$LDFLAGS -z now"],[],[]) 260 | 261 | dnl Add glibc hardening 262 | CPPFLAGS="$CPPFLAGS -D_FORTIFY_SOURCE=2" 263 | 264 | ############################################################################## 265 | # 10. Finish up 266 | ############################################################################## 267 | 268 | AC_CONFIG_FILES([ 269 | Makefile 270 | extras/Makefile 271 | src/Makefile 272 | src/bin/Makefile 273 | src/bin/torsocks 274 | src/common/Makefile 275 | src/lib/Makefile 276 | tests/Makefile 277 | tests/unit/Makefile 278 | tests/utils/Makefile 279 | tests/utils/tap/Makefile 280 | doc/Makefile 281 | ]) 282 | 283 | AC_OUTPUT 284 | -------------------------------------------------------------------------------- /doc/Makefile.am: -------------------------------------------------------------------------------- 1 | # Install configuration file 2 | confdir = $(CONFDIR)/tor 3 | dist_conf_DATA = torsocks.conf 4 | 5 | dist_man1_MANS = torsocks.1 6 | dist_man5_MANS = torsocks.conf.5 7 | dist_man8_MANS = torsocks.8 8 | 9 | dist_doc_DATA = socks/SOCKS5 socks/socks-extensions.txt notes/DEBUG 10 | 11 | -------------------------------------------------------------------------------- /doc/notes/DEBUG: -------------------------------------------------------------------------------- 1 | You can set breakpoints in libtorsocks using the following technique. Say you 2 | want to debug torsocks when it's wrapping a program called gethostbyaddr, that 3 | calls gethostbyaddr(): 4 | 5 | gdb ./gethostbyaddr 6 | set environment LD_PRELOAD /path/to/libtorsocks.so 7 | b our_gethostbyaddr 8 | run 9 | -------------------------------------------------------------------------------- /doc/proposals/01-Thread-safe-design.txt: -------------------------------------------------------------------------------- 1 | Date: 09/06/2013 2 | Author: David Goulet 3 | Contributors: 4 | * Mathieu Desnoyers 5 | 6 | This document details the design of torsocks locking for thread safety. 7 | 8 | The basis is that at *any* time any thread can interact with Torsocks 9 | (connect(2), DNS resolution, ...). Considering that, some sort of 10 | synchronization is needed since torsocks needs to keep track of per socket 11 | connection. They are kept in a central registry that every thread needs to 12 | access. 13 | 14 | The reason why it needs to be shared accross threads is because of fd passing. 15 | It is possible and even not uncommon that threads exchange file descriptor(s) so 16 | we can't keep a registry of connections using TLS (Thread Local Storage). 17 | Furthermore, a process could easily, for instance, close(2) a socket within a 18 | signal handler making Torsocks access thread storage inside a signal handler and 19 | this SHOULD NOT be done, just never. 20 | 21 | Considering the above, a locking mechanism is needed to protect the registry. 22 | Insertion, deletion and lookup in that registry CAN occur at the same time so a 23 | mutex has to be used to protect any action *on* it. This protection is provided 24 | by a mutex named "registry lock". 25 | 26 | Now, the objects inside that registry have to be protected during their life 27 | time (as long as a reference is held) after a lookup. To protect the free() from 28 | concurrent access, a refcount is used. Basically, each possible action on a 29 | connection object checks if the connection refcount is down to 0. If so, this 30 | means that no one is holding a reference to the object and it is ready to be 31 | destroyed. For that, the refcount needs to start with a value of 1. 32 | 33 | For this scheme to work, the connection object MUST be immutable once created. 34 | Any part that can change during the lifetime of the connection object MUST be 35 | protected with a mutex. 36 | 37 | This mechanism is used to avoid heavy contention on the registry lock. Without 38 | the refcount, a connection would have to be protected within the registry lock 39 | to avoid race between an access to the object and freeing it. As long as the 40 | lookups in the registry are not that frequent, this should scale since the 41 | critical section is pretty short. 42 | 43 | Here is the algorithm for a read/write and destroy operation. 44 | 45 | Prerequisites: 46 | ---- 47 | Refcount of a connection object starts at 1. When down to 0, it can be 48 | destroyed. 49 | 50 | Add to registry (e.g.: connect(2)): 51 | ---- 52 | 1) lock(registry) 53 | 2) new_conn refcount = 1; 54 | 3) add to registry 55 | /* We could also make a lookup for duplicates. */ 56 | 4) unlock(registry) 57 | 58 | Read/Write op. (e.g.: DNS Lookup): 59 | ---- 60 | 1) lock(registry) 61 | 2) conn = lookup 62 | 3) if conn: 63 | 4) atomic_inc(conn refcount) 64 | 5) unlock(registry) 65 | 6) [action using the conn] 66 | 7) if atomic_dec_return(conn refcount) == 0: 67 | /* 68 | * This is safe because at this point the connection object is not visible 69 | * anymore to any thread so we can safely free the object after unlocking it. 70 | */ 71 | 8) free conn 72 | 73 | Destroy from registry (e.g.: close(2)): 74 | ---- 75 | 1) lock(registry) 76 | 2) conn = lookup 77 | 3) if conn: 78 | /* 79 | * Make sure the connection object is not visible once we release the registry 80 | * lock. Note that we DO NOT increment the refcount here because we are on the 81 | * destroy path so we have to make the refcount come down to 0. 82 | */ 83 | 4) remove from registry 84 | 5) unlock(registry) 85 | 6) if atomic_dec_return(conn refcount) == 0: 86 | 7) free(conn) 87 | -------------------------------------------------------------------------------- /doc/socks/SOCKS5: -------------------------------------------------------------------------------- 1 | http://www.ietf.org/rfc/rfc1928.txt 2 | 3 | -------------------------------------------------------------------------------- /doc/socks/socks-extensions.txt: -------------------------------------------------------------------------------- 1 | $Id: socks-extensions.txt,v 1.1 2008-06-18 21:17:02 hoganrobert Exp $ 2 | Tor's extensions to the SOCKS protocol 3 | 4 | 1. Overview 5 | 6 | The SOCKS protocol provides a generic interface for TCP proxies. Client 7 | software connects to a SOCKS server via TCP, and requests a TCP connection 8 | to another address and port. The SOCKS server establishes the connection, 9 | and reports success or failure to the client. After the connection has 10 | been established, the client application uses the TCP stream as usual. 11 | 12 | Tor supports SOCKS4 as defined in [1], SOCKS4A as defined in [2], and 13 | SOCKS5 as defined in [3]. 14 | 15 | The stickiest issue for Tor in supporting clients, in practice, is forcing 16 | DNS lookups to occur at the OR side: if clients do their own DNS lookup, 17 | the DNS server can learn which addresses the client wants to reach. 18 | SOCKS4 supports addressing by IPv4 address; SOCKS4A is a kludge on top of 19 | SOCKS4 to allow addressing by hostname; SOCKS5 supports IPv4, IPv6, and 20 | hostnames. 21 | 22 | 1.1. Extent of support 23 | 24 | Tor supports the SOCKS4, SOCKS4A, and SOCKS5 standards, except as follows: 25 | 26 | BOTH: 27 | - The BIND command is not supported. 28 | 29 | SOCKS4,4A: 30 | - SOCKS4 usernames are ignored. 31 | 32 | SOCKS5: 33 | - The (SOCKS5) "UDP ASSOCIATE" command is not supported. 34 | - IPv6 is not supported in CONNECT commands. 35 | - Only the "NO AUTHENTICATION" (SOCKS5) authentication method [00] is 36 | supported. 37 | 38 | 2. Name lookup 39 | 40 | As an extension to SOCKS4A and SOCKS5, Tor implements a new command value, 41 | "RESOLVE" [F0]. When Tor receives a "RESOLVE" SOCKS command, it initiates 42 | a remote lookup of the hostname provided as the target address in the SOCKS 43 | request. The reply is either an error (if the address couldn't be 44 | resolved) or a success response. In the case of success, the address is 45 | stored in the portion of the SOCKS response reserved for remote IP address. 46 | 47 | (We support RESOLVE in SOCKS4 too, even though it is unnecessary.) 48 | 49 | For SOCKS5 only, we support reverse resolution with a new command value, 50 | "RESOLVE_PTR" [F1]. In response to a "RESOLVE_PTR" SOCKS5 command with 51 | an IPv4 address as its target, Tor attempts to find the canonical 52 | hostname for that IPv4 record, and returns it in the "server bound 53 | address" portion of the reply. 54 | (This command was not supported before Tor 0.1.2.2-alpha.) 55 | 56 | 3. Other command extensions. 57 | 58 | Tor 0.1.2.4-alpha added a new command value: "CONNECT_DIR" [F2]. 59 | In this case, Tor will open an encrypted direct TCP connection to the 60 | directory port of the Tor server specified by address:port (the port 61 | specified should be the ORPort of the server). It uses a one-hop tunnel 62 | and a "BEGIN_DIR" relay cell to accomplish this secure connection. 63 | 64 | The F2 command value was removed in Tor 0.2.0.10-alpha in favor of a 65 | new use_begindir flag in edge_connection_t. 66 | 67 | 4. HTTP-resistance 68 | 69 | Tor checks the first byte of each SOCKS request to see whether it looks 70 | more like an HTTP request (that is, it starts with a "G", "H", or "P"). If 71 | so, Tor returns a small webpage, telling the user that his/her browser is 72 | misconfigured. This is helpful for the many users who mistakenly try to 73 | use Tor as an HTTP proxy instead of a SOCKS proxy. 74 | 75 | References: 76 | [1] http://archive.socks.permeo.com/protocol/socks4.protocol 77 | [2] http://archive.socks.permeo.com/protocol/socks4a.protocol 78 | [3] SOCKS5: RFC1928 79 | 80 | -------------------------------------------------------------------------------- /doc/torsocks.1: -------------------------------------------------------------------------------- 1 | .TH "TORSOCKS" "1" "March 3rd, 2014" "" "" 2 | 3 | .SH NAME 4 | torsocks \(em Shell wrapper to simplify the use of the torsocks(8) library to 5 | transparently torify an application. 6 | 7 | .SH SYNOPSIS 8 | 9 | .PP 10 | torsocks [OPTIONS] [COMMAND [ARG ...]] 11 | 12 | .SH DESCRIPTION 13 | 14 | \fBtorsocks\fP is a wrapper between the torsocks library and the application in 15 | order to make every Internet communication go through the Tor network. 16 | 17 | By default, torsocks will assume that it should connect to the Tor SOCKS proxy 18 | running at 127.0.0.1 on port 9050 being the defaults of the Tor daemon. 19 | 20 | In order to use a configuration file, torsocks tries to read the 21 | \fB/etc/tor/torsocks.conf\fP file or look for the environment variable 22 | TORSOCKS_CONF_FILE with the location of the file. If that file cannot be read, 23 | torsocks will use sensible defaults for most Tor installations. 24 | 25 | For further information on configuration, see 26 | .BR torsocks.conf(5). 27 | 28 | .SH OPTIONS 29 | 30 | .TP 31 | .BR "\-h, \-\-help" 32 | Show summary of possible options and commands. 33 | .TP 34 | .BR "\-\-shell" 35 | Create a new shell with LD_PRELOAD including \fBtorsocks(8)\fP. 36 | .TP 37 | .BR "\-\-version" 38 | Show version. 39 | .TP 40 | .BR "\-u, \-\-user" 41 | Set username for the SOCKS5 authentication. Use for circuit isolation in Tor. 42 | Note that you MUST have a password set either by the command line, environment 43 | variable or configuration file (torsocks.conf(5). 44 | .TP 45 | .BR "\-p, \-\-pass" 46 | Set password for the SOCKS5 authentication. Use for circuit isolation in Tor. 47 | Note that you MUST have a username set either by the command line, environment 48 | variable or configuration file (torsocks.conf(5)). 49 | .TP 50 | .BR "\-a, \-\-address" 51 | Set Tor address. 52 | .TP 53 | .BR "\-P, \-\-port" 54 | Set Tor port. 55 | .TP 56 | .BR "\-i, \-\-isolate" 57 | Automatic tor isolation. Set the username and password for the SOCKS5 58 | authentication method to a PID/current time based value automatically. Username 59 | and Password MUST NOT be set. 60 | .TP 61 | .BR "\-d, \-\-debug" 62 | Activate the debug mode. Output will be written on stderr. 63 | .TP 64 | .BR "\-q, \-\-quiet" 65 | Suppress every log messages (even errors). 66 | .TP 67 | .BR "on | off" 68 | This option adds or removes \fBtorsocks(8)\fP from the LD_PRELOAD environment 69 | variable for the current shell. If you want to use this option, you HAVE to 70 | source torsocks from your shell. 71 | .br 72 | 73 | .nf 74 | Add the torsocks library to LD_PRELOAD 75 | $ . torsocks on 76 | .br 77 | Remove the torsocks library from LD_PRELOAD 78 | $ . torsocks off 79 | .fi 80 | .TP 81 | .BR "show | sh" 82 | Show the current value of the LD_PRELOAD environment variable. 83 | 84 | .SH "ENVIRONMENT VARIABLES" 85 | .PP 86 | Please see \fBtorsocks(8)\fP for more detail on possible environment variables. 87 | .PP 88 | 89 | .SH "SEE ALSO" 90 | .BR torsocks(8), 91 | .BR torsocks.conf(5) 92 | 93 | .SH "CREDITS" 94 | 95 | .PP 96 | torsocks is distributed under the GNU General Public License version 2. 97 | .PP 98 | A Web site is available at https://www.torproject.org for more information. 99 | .PP 100 | You can also find the source code at https://git.torproject.org. 101 | .PP 102 | Mailing list for help is and for development 103 | use . You can find the project also on IRC server 104 | irc.oftc.net (OFTC) in #tor and #tor-dev. 105 | .PP 106 | 107 | .SH AUTHOR 108 | torsocks was originally written by Robert Hogan and has been rewritten by David 109 | Goulet in 2013. 110 | .PP 111 | -------------------------------------------------------------------------------- /doc/torsocks.8: -------------------------------------------------------------------------------- 1 | .TH "TORSOCKS" "8" "August 24th, 2013" "" "" 2 | 3 | .SH NAME 4 | 5 | torsocks \(em Library for intercepting outgoing network connections and 6 | redirecting them through the Tor SOCKS proxy. 7 | 8 | .SH DESCRIPTION 9 | 10 | Torsocks library overloads the libc symbols use for Internet communication such 11 | as \fBconnect(2)\fP system call. Using that technique, the library sends 12 | everything through the Tor network including DNS resolution done by the 13 | application. 14 | 15 | For DNS, \fBgethostbyname(3)\fP family functions are rerouted through Tor. 16 | Please note that the ISC res_* API is currently not supported. 17 | 18 | Here is an example on how to use torsocks library with \fBssh(1)\fP: 19 | .br 20 | 21 | $ LD_PRELOAD=/path/to/libtorsocks.so ssh -l kalexander -p 1234 prism.nsa.gov 22 | [...] 23 | 24 | .SH SHELL USAGE 25 | 26 | Set LD_PRELOAD to load the library then use applications as normal. The syntax 27 | to force preload of the library for different shells is specified below: 28 | 29 | Bash, Ksh and Bourne shell: 30 | 31 | $ export LD_PRELOAD=/path/to/libtorsocks.so 32 | 33 | C Shell: 34 | 35 | $ setenv LD_PRELOAD=/path/to/libtorsocks.so 36 | 37 | This process can be automated (for Bash, Bourne and Korn shell users) for a 38 | single command or for all commands in a shell session by using the 39 | \fBtorsocks(1)\fP script. 40 | 41 | You can also setup \fBtorsocks(1)\fP in such a way that all processes 42 | automatically use it, a very useful configuration. Please refer to the torsocks 43 | script documentation for more information. 44 | 45 | .SH "ENVIRONMENT VARIABLES" 46 | 47 | .PP 48 | .IP TORSOCKS_CONF_FILE 49 | This environment variable overrides the default location of the torsocks 50 | configuration file. This variable is not honored if the program torsocks is 51 | embedded in is setuid. 52 | 53 | .PP 54 | .IP TORSOCKS_LOG_LEVEL 55 | Enable logging level of torsocks library. By default, warnings and errors are 56 | printed (level 3). Note that each level includes the lower ones except the 1 57 | which disables any possible logging. (default: 3) 58 | 59 | .TS 60 | tab (@); 61 | l lx. 62 | 1@T{ 63 | No log at all. 64 | T} 65 | 2@T{ 66 | Error messages. 67 | T} 68 | 3@T{ 69 | Warning messages. 70 | T} 71 | 4@T{ 72 | Notice messages. 73 | T} 74 | 5@T{ 75 | Debug messages. 76 | T} 77 | .TE 78 | 79 | .PP 80 | .IP TORSOCKS_LOG_TIME 81 | Control whether or not the time is added to each logging line. (default: 1) 82 | 83 | .PP 84 | .IP TORSOCKS_LOG_FILE_PATH 85 | If set, torsocks will log in the file set by this variable. (default: stderr) 86 | 87 | .PP 88 | .IP TORSOCKS_USERNAME 89 | Set the username for the SOCKS5 authentication method. Password MUST be set 90 | also with the variable below. 91 | 92 | .PP 93 | .IP TORSOCKS_PASSWORD 94 | Set the password for the SOCKS5 authentication method. Username MUST be set 95 | also with the variable above. 96 | 97 | .PP 98 | .IP TORSOCKS_TOR_ADDRESS 99 | Set the Tor address. (default: 127.0.0.1) 100 | 101 | .PP 102 | .IP TORSOCKS_TOR_PORT 103 | Set the Tor port. (default: 9050) 104 | 105 | .PP 106 | .IP TORSOCKS_ALLOW_INBOUND 107 | Allow inbound connections so the application can accept and listen for 108 | connections. 109 | 110 | .PP 111 | .IP TORSOCKS_ISOLATE_PID 112 | Set the username and password for the SOCKS5 authentication method to a 113 | PID/current time based value automatically. Username and Password MUST NOT 114 | be set. 115 | 116 | .SH KNOWN ISSUES 117 | 118 | .SS DNS 119 | Torsocks is not able to send DNS queries through Tor since UDP is not 120 | supported. Thus, any UDP socket is denied. However, DNS queries that can be 121 | intercept are sent to Tor and sent back to the caller. 122 | .SS ERRORS 123 | Torsocks might generate error messages and print them to stderr when there are 124 | problems with the configuration file or the SOCKS negotiation with the Tor 125 | daemon. The TORSOCKS_LOG_LEVEL environment variable controls that behavior as 126 | well as the log file option. Keep in mind that this library can output on the 127 | stderr of the application. 128 | 129 | .SH LIMITATIONS 130 | 131 | Outgoing TCP connections can only be proxified through the Tor network. 132 | 133 | Torsocks forces the libc resolver to use TCP for name queries, if it does this 134 | it does it regardless of whether or not the DNS to be queried is local or not. 135 | This introduces overhead and should only be used when needed. 136 | 137 | Torsocks uses ELF dynamic loader features to intercept dynamic function calls 138 | from programs in which it is embedded. As a result, non-ELF executables, or 139 | executables that make system calls directly with the system call trap (int 140 | 0x80) are not supported. 141 | 142 | .SH FILES 143 | /etc/tor/torsocks.conf - default torsocks configuration file 144 | 145 | .SH SEE ALSO 146 | .BR torsocks.conf(5), 147 | .BR torsocks(1) 148 | 149 | .SH AUTHOR 150 | David Goulet 151 | -------------------------------------------------------------------------------- /doc/torsocks.conf: -------------------------------------------------------------------------------- 1 | # This is the configuration for libtorsocks (transparent socks) for use 2 | # with tor, which is providing a socks server on port 9050 by default. 3 | # 4 | # Lines beginning with # and blank lines are ignored 5 | # Much more documentation than provided in these comments can be found in 6 | # 7 | # torsocks.conf(5), torsocks(1) and torsocks(8) manpages. 8 | 9 | # Default Tor address and port. By default, Tor will listen on localhost for 10 | # any SOCKS connection and relay the traffic on the Tor network. 11 | TorAddress 127.0.0.1 12 | TorPort 9050 13 | 14 | # Tor hidden sites do not have real IP addresses. This specifies what range of 15 | # IP addresses will be handed to the application as "cookies" for .onion names. 16 | # Of course, you should pick a block of addresses which you aren't going to 17 | # ever need to actually connect to. This is similar to the MapAddress feature 18 | # of the main tor daemon. 19 | OnionAddrRange 127.42.42.0/24 20 | 21 | # SOCKS5 Username and Password. This is used to isolate the torsocks connection 22 | # circuit from other streams in Tor. Use with option IsolateSOCKSAuth (on by 23 | # default) in tor(1). TORSOCKS_USERNAME and TORSOCKS_PASSWORD environment 24 | # variable overrides these options. 25 | #SOCKS5Username 26 | #SOCKS5Password 27 | 28 | # Set Torsocks to accept inbound connections. If set to 1, listen() and 29 | # accept() will be allowed to be used with non localhost address. (Default: 0) 30 | #AllowInbound 1 31 | 32 | # Set Torsocks to allow outbound connections to the loopback interface. 33 | # If set to 1, connect() will be allowed to be used to the loopback interface 34 | # bypassing Tor. If set to 2, in addition to TCP connect(), UDP operations to 35 | # the loopback interface will also be allowed, bypassing Tor. This option 36 | # should not be used by most users. (Default: 0) 37 | #AllowOutboundLocalhost 1 38 | 39 | # Set Torsocks to use an automatically generated SOCKS5 username/password based 40 | # on the process ID and current time, that makes the connections to Tor use a 41 | # different circuit from other existing streams in Tor on a per-process basis. 42 | # If set, the SOCKS5Username and SOCKS5Password options must not be set. 43 | # (Default: 0) 44 | #IsolatePID 1 45 | -------------------------------------------------------------------------------- /doc/torsocks.conf.5: -------------------------------------------------------------------------------- 1 | .TH "TORSOCKS.CONF" "5" "August 24th, 2013" "" "" 2 | 3 | .SH NAME 4 | torsocks.conf \(em Configuration file for torsocks(8) 5 | 6 | .SH SUMMARY 7 | 8 | By default, torsocks will assume that it should connect to the Tor SOCKS proxy 9 | running at 127.0.0.1 on port 9050. This is the default address and port for 10 | Tor's socks server on most installations. If you are running a normal Tor 11 | installation and have no special requirements, then you should not need to 12 | create, edit or invoke a configuration file when using torsocks. 13 | 14 | Your installation of torsocks includes a default configuration file 15 | that contains values sensible for use with most Tor installations. The 16 | installation location for your default configuration file is: 17 | 18 | /etc/tor/torsocks.conf 19 | 20 | In order to use a configuration file, you must set the environment variable 21 | TORSOCKS_CONF_FILE with the location of the file. 22 | 23 | If TORSOCKS_CONF_FILE is not set, torsocks will attempt to read the 24 | configuration file at /etc/tor/torsocks.conf. If that file cannot be read, 25 | torsocks will use sensible defaults for most Tor installations, i.e. it will 26 | assume that you want to use a SOCKS proxy running at 127.0.0.1 (localhost) on 27 | port 9050. 28 | 29 | .SH CONFIGURATION 30 | 31 | .SS SYNTAX 32 | The basic structure of all lines in the configuration file is: 33 | 34 | .RS 35 | 36 | .RE 37 | 38 | Empty lines are ignored and all input on a line after a '#' character is 39 | ignored. 40 | 41 | .SS DIRECTIVES 42 | The following directives are used in the torsocks configuration file: 43 | 44 | .TP 45 | .I TorAddress ip_addr 46 | The IP address of the Tor SOCKS server (e.g "server = 10.1.4.253"). Only one 47 | server may be specified. Currently, torsocks does NOT support hostname. 48 | (default: 127.0.0.1) 49 | 50 | .TP 51 | .I TorPort port 52 | The port on which the Tor SOCKS server receives requests. (default: 9050) 53 | 54 | .TP 55 | .I OnionAddrRange subnet/mask 56 | Tor hidden sites do not have real IP addresses. This specifies what range of IP 57 | addresses will be handed to the application as "cookies" for .onion names. Of 58 | course, you should pick a block of addresses which you aren't going to ever 59 | need to actually connect to. This is similar to the MapAddress feature of the 60 | main tor daemon. (default: 127.42.42.0/24) 61 | 62 | .TP 63 | .I SOCKS5Username username 64 | Username to use for SOCKS5 authentication method that makes the connections to 65 | Tor to use a different circuit from other existing streams. If set, the 66 | SOCKS5Password must be specified also. (Default: none). 67 | 68 | .TP 69 | .I SOCKS5Password password 70 | Password to use for SOCKS5 authentication method that makes the connections to 71 | Tor to use a different circuit from other existing streams. If set, the 72 | SOCKS5Username must be specified also. (Default: none). 73 | 74 | .TP 75 | .I AllowInbound 0|1 76 | Allow inbound connections meaning that listen() and accept()/accept4() will be 77 | allowed for non localhost address so the applicaton can handle incoming 78 | connection. Note that Unix socket are allowed. (Default: 0) 79 | 80 | .TP 81 | .I AllowOutboundLocalhost 0|1|2 82 | Allow outbound connections to the loopback interface meaning that connect() 83 | will be allowed to connect to localhost addresses bypassing Tor. If set to 1, 84 | TCP connections will be allowed. If set to 2, both TCP/IP and UDP connections 85 | will be allowed. This option should not be used by most users. (Default: 0) 86 | 87 | .TP 88 | .I IsolatePID 0|1 89 | Set Torsocks to use an automatically generated SOCKS5 username/password 90 | based on the process ID and current time, that makes the connections to Tor 91 | use a different circuit from other existing streams in Tor on a per-process 92 | basis. If set, the SOCKS5Username and SOCKS5Password options must not be 93 | set. (Default: 0) 94 | 95 | .SH EXAMPLE 96 | $ export TORSOCKS_CONF_FILE=$PWD/torsocks.conf 97 | $ torsocks ssh account@sshserver.com 98 | 99 | .SH SEE ALSO 100 | .BR torsocks(1), 101 | .BR torsocks(8), 102 | 103 | .SH AUTHOR 104 | David Goulet 105 | -------------------------------------------------------------------------------- /extras/Makefile.am: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dgoulet/torsocks/d4b0a84bdf2a1895c8ec3091dc2767fd9f8c2d66/extras/Makefile.am -------------------------------------------------------------------------------- /extras/torsocks-bash_completion: -------------------------------------------------------------------------------- 1 | #-*- mode: shell-script;-*- 2 | 3 | complete -F _command torsocks 4 | -------------------------------------------------------------------------------- /extras/torsocks-zsh_completion: -------------------------------------------------------------------------------- 1 | #compdef - torsocks 2 | 3 | # precommands is made local in _main_complete 4 | precommands+=($words[1]) 5 | 6 | shift words 7 | (( CURRENT-- )) 8 | 9 | _normal 10 | -------------------------------------------------------------------------------- /include/.placeholder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dgoulet/torsocks/d4b0a84bdf2a1895c8ec3091dc2767fd9f8c2d66/include/.placeholder -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = common lib bin 2 | -------------------------------------------------------------------------------- /src/bin/Makefile.am: -------------------------------------------------------------------------------- 1 | # Makefile used by configure to create real Makefile 2 | 3 | libdir = @libdir@/torsocks 4 | 5 | # Install invocation scripts 6 | bin_SCRIPTS = torsocks 7 | INSTALL_SCRIPT = $(install_sh) -c -m 755 8 | 9 | # Install main library to $(prefix)/lib/tor (must match torsocks.in) 10 | CLEANFILES = torsocks 11 | -------------------------------------------------------------------------------- /src/common/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src 2 | 3 | AM_CFLAGS = -fno-strict-aliasing 4 | 5 | noinst_LTLIBRARIES = libcommon.la 6 | libcommon_la_SOURCES = log.c log.h config-file.c config-file.h utils.c utils.h \ 7 | compat.c compat.h socks5.c socks5.h defaults.h macros.h \ 8 | connection.c connection.h ht.h ref.h onion.c onion.h 9 | -------------------------------------------------------------------------------- /src/common/compat.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with 14 | * this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #include 19 | 20 | #include "compat.h" 21 | 22 | #if (defined(__linux__) || defined(__GLIBC__) || defined(__FreeBSD__) || \ 23 | defined(__darwin__) || defined(__NetBSD__)) 24 | 25 | /* 26 | * Initialize a pthread mutex. This never fails. 27 | */ 28 | void tsocks_mutex_init(tsocks_mutex_t *m) 29 | { 30 | assert(m); 31 | pthread_mutex_init(&m->mutex, NULL); 32 | } 33 | 34 | /* 35 | * Destroy a pthread mutex. This never fails. 36 | */ 37 | void tsocks_mutex_destroy(tsocks_mutex_t *m) 38 | { 39 | assert(m); 40 | pthread_mutex_destroy(&m->mutex); 41 | } 42 | 43 | /* 44 | * Use pthread mutex lock and assert on any error. 45 | */ 46 | void tsocks_mutex_lock(tsocks_mutex_t *m) 47 | { 48 | int ret; 49 | 50 | assert(m); 51 | ret = pthread_mutex_lock(&m->mutex); 52 | /* 53 | * Unable to lock the mutex could lead to undefined behavior and potential 54 | * security issues. Stop everything so torsocks can't continue. 55 | */ 56 | assert(!ret); 57 | } 58 | 59 | /* 60 | * Use pthread mutex unlock and assert on any error. 61 | */ 62 | void tsocks_mutex_unlock(tsocks_mutex_t *m) 63 | { 64 | int ret; 65 | 66 | assert(m); 67 | ret = pthread_mutex_unlock(&m->mutex); 68 | /* 69 | * Unable to unlock the mutex could lead to undefined behavior and potential 70 | * security issues. Stop everything so torsocks can't continue. 71 | */ 72 | assert(!ret); 73 | } 74 | 75 | /* 76 | * Call the given routine once, and only once. tsocks_once returning 77 | * guarantees that the routine has succeded. 78 | */ 79 | void tsocks_once(tsocks_once_t *o, void (*init_routine)(void)) 80 | { 81 | 82 | /* Why, yes, pthread_once(3P) exists. Said routine requires linking in a 83 | * real pthread library on Linux, while this does not and will do the right 84 | * thing even with the stub implementation. */ 85 | assert(o); 86 | 87 | /* This looks scary and incorrect, till you realize that the 88 | * pthread_mutex routines include memory barriers. */ 89 | if (!o->once) { 90 | return; 91 | } 92 | tsocks_mutex_lock(&o->mutex); 93 | if (o->once) { 94 | init_routine(); 95 | o->once = 0; 96 | } 97 | tsocks_mutex_unlock(&o->mutex); 98 | } 99 | 100 | #endif /* __linux__, __GLIBC__, __darwin__, __FreeBSD__, __NetBSD__ */ 101 | -------------------------------------------------------------------------------- /src/common/compat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with 14 | * this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #ifndef TORSOCKS_COMPAT_H 19 | #define TORSOCKS_COMPAT_H 20 | 21 | #if (defined(__APPLE__) && defined(__MACH__) && !defined(__darwin__)) 22 | #define __darwin__ 1 23 | #endif 24 | 25 | #if (defined(__linux__) || defined(__GLIBC__) || defined(__FreeBSD__) || \ 26 | defined(__darwin__) || defined(__NetBSD__)) 27 | 28 | #ifndef RTLD_NEXT 29 | #define RTLD_NEXT ((void *) -1) 30 | #endif 31 | 32 | #include 33 | 34 | typedef struct tsocks_mutex_t { 35 | pthread_mutex_t mutex; 36 | } tsocks_mutex_t; 37 | 38 | /* Define a tsock mutex variable with the mutex statically initialized. */ 39 | #define TSOCKS_MUTEX_INIT { .mutex = PTHREAD_MUTEX_INITIALIZER } 40 | #define TSOCKS_INIT_MUTEX(name) \ 41 | tsocks_mutex_t name = TSOCKS_MUTEX_INIT 42 | 43 | void tsocks_mutex_init(tsocks_mutex_t *m); 44 | void tsocks_mutex_destroy(tsocks_mutex_t *m); 45 | void tsocks_mutex_lock(tsocks_mutex_t *m); 46 | void tsocks_mutex_unlock(tsocks_mutex_t *m); 47 | 48 | typedef struct tsocks_once_t { 49 | int once:1; 50 | tsocks_mutex_t mutex; 51 | } tsocks_once_t; 52 | 53 | /* Define a tsock once variable, statically initialized. */ 54 | #define TSOCKS_INIT_ONCE(name) \ 55 | tsocks_once_t name = { .once = 1, .mutex = TSOCKS_MUTEX_INIT } 56 | 57 | void tsocks_once(tsocks_once_t *o, void (*init_routine)(void)); 58 | 59 | #else 60 | #error "OS not supported." 61 | #endif /* __linux__, __GLIBC__, __darwin__, __FreeBSD__, __NetBSD__ */ 62 | 63 | #if defined(__linux__) 64 | #include 65 | #include 66 | 67 | /* 68 | * Some old system requires kernel headers for those values. If they are not 69 | * defined, set them to a bad syscall value. Just to be clear, if the value is 70 | * undefined, tsocks syscall() will DENY the real syscall if caught. 71 | * 72 | * The values are not the same per syscall here so we don't end up with 73 | * duplicates in the switch case in the tsocks sycall wrapper. 74 | */ 75 | #ifndef __NR_socket 76 | #define __NR_socket -1 77 | #endif 78 | #ifndef __NR_connect 79 | #define __NR_connect -2 80 | #endif 81 | #ifndef __NR_close 82 | #define __NR_close -3 83 | #endif 84 | #ifndef __NR_mmap 85 | #define __NR_mmap -4 86 | #endif 87 | #ifndef __NR_munmap 88 | #define __NR_munmap -5 89 | #endif 90 | #ifndef __NR_accept 91 | #define __NR_accept -6 92 | #endif 93 | #ifndef __NR_getpeername 94 | #define __NR_getpeername -7 95 | #endif 96 | #ifndef __NR_listen 97 | #define __NR_listen -8 98 | #endif 99 | #ifndef __NR_recvmsg 100 | #define __NR_recvmsg -9 101 | #endif 102 | #ifndef __NR_gettid 103 | #define __NR_gettid -10 104 | #endif 105 | #ifndef __NR_getrandom 106 | #define __NR_getrandom -11 107 | #endif 108 | #ifndef __NR_futex 109 | #define __NR_futex -12 110 | #endif 111 | #ifndef __NR_accept4 112 | #define __NR_accept4 -13 113 | #endif 114 | #ifndef __NR_sched_getaffinity 115 | #define __NR_sched_getaffinity -14 116 | #endif 117 | #ifndef __NR_seccomp 118 | #define __NR_seccomp -15 119 | #endif 120 | #ifndef __NR_gettimeofday 121 | #define __NR_gettimeofday -16 122 | #endif 123 | #ifndef __NR_clock_gettime 124 | #define __NR_clock_gettime -17 125 | #endif 126 | #ifndef __NR_fork 127 | #define __NR_fork -18 128 | #endif 129 | #ifndef __NR_memfd_create 130 | #define __NR_memfd_create -19 131 | #endif 132 | #ifndef __NR_getdents 133 | #define __NR_getdents -20 134 | #endif 135 | #ifndef __NR_getdents64 136 | #define __NR_getdents64 -21 137 | #endif 138 | 139 | #define TSOCKS_NR_SOCKET __NR_socket 140 | #define TSOCKS_NR_CONNECT __NR_connect 141 | #define TSOCKS_NR_CLOSE __NR_close 142 | #define TSOCKS_NR_MMAP __NR_mmap 143 | #define TSOCKS_NR_MUNMAP __NR_munmap 144 | #define TSOCKS_NR_ACCEPT __NR_accept 145 | #define TSOCKS_NR_GETPEERNAME __NR_getpeername 146 | #define TSOCKS_NR_LISTEN __NR_listen 147 | #define TSOCKS_NR_RECVMSG __NR_recvmsg 148 | #define TSOCKS_NR_GETTID __NR_gettid 149 | #define TSOCKS_NR_GETRANDOM __NR_getrandom 150 | #define TSOCKS_NR_FUTEX __NR_futex 151 | #define TSOCKS_NR_ACCEPT4 __NR_accept4 152 | #define TSOCKS_NR_SCHED_GETAFFINITY __NR_sched_getaffinity 153 | #define TSOCKS_NR_SECCOMP __NR_seccomp 154 | #define TSOCKS_NR_GETTIMEOFDAY __NR_gettimeofday 155 | #define TSOCKS_NR_CLOCK_GETTIME __NR_clock_gettime 156 | #define TSOCKS_NR_FORK __NR_fork 157 | #define TSOCKS_NR_MEMFD_CREATE __NR_memfd_create 158 | #define TSOCKS_NR_GETDENTS __NR_getdents 159 | #define TSOCKS_NR_GETDENTS64 __NR_getdents64 160 | 161 | /* 162 | * Despite glibc providing wrappers for these calls for a long time 163 | * (as in "even Debian squeeze has all the wrappers"), libuv decided to 164 | * use syscall() to invoke them instead. 165 | */ 166 | 167 | #include 168 | #include 169 | #include 170 | 171 | #ifndef __NR_epoll_create1 172 | #define __NR_epoll_create1 -128 173 | #endif 174 | #ifndef __NR_epoll_wait 175 | #define __NR_epoll_wait -129 176 | #endif 177 | #ifndef __NR_epoll_pwait 178 | #define __NR_epoll_pwait -130 179 | #endif 180 | #ifndef __NR_epoll_ctl 181 | #define __NR_epoll_ctl -131 182 | #endif 183 | #ifndef __NR_eventfd2 184 | #define __NR_eventfd2 -132 185 | #endif 186 | #ifndef __NR_inotify_init1 187 | #define __NR_inotify_init1 -133 188 | #endif 189 | #ifndef __NR_inotify_add_watch 190 | #define __NR_inotify_add_watch -134 191 | #endif 192 | #ifndef __NR_inotify_rm_watch 193 | #define __NR_inotify_rm_watch -135 194 | #endif 195 | 196 | #define TSOCKS_NR_EPOLL_CREATE1 __NR_epoll_create1 197 | #define TSOCKS_NR_EPOLL_WAIT __NR_epoll_wait 198 | #define TSOCKS_NR_EPOLL_PWAIT __NR_epoll_pwait 199 | #define TSOCKS_NR_EPOLL_CTL __NR_epoll_ctl 200 | #define TSOCKS_NR_EVENTFD2 __NR_eventfd2 201 | #define TSOCKS_NR_INOTIFY_INIT1 __NR_inotify_init1 202 | #define TSOCKS_NR_INOTIFY_ADD_WATCH __NR_inotify_add_watch 203 | #define TSOCKS_NR_INOTIFY_RM_WATCH __NR_inotify_rm_watch 204 | 205 | #endif /* __linux__ */ 206 | 207 | #if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__darwin__) || defined(__NetBSD__)) 208 | 209 | #include 210 | #include 211 | 212 | #if defined(__NetBSD__) 213 | #define SYS_socket SYS___socket30 214 | #endif 215 | 216 | #define TSOCKS_NR_SOCKET SYS_socket 217 | #define TSOCKS_NR_CONNECT SYS_connect 218 | #define TSOCKS_NR_CLOSE SYS_close 219 | #define TSOCKS_NR_MMAP SYS_mmap 220 | #define TSOCKS_NR_MUNMAP SYS_munmap 221 | #define TSOCKS_NR_ACCEPT SYS_accept 222 | #define TSOCKS_NR_GETPEERNAME SYS_getpeername 223 | #define TSOCKS_NR_LISTEN SYS_listen 224 | #define TSOCKS_NR_RECVMSG SYS_recvmsg 225 | 226 | #endif /* __FreeBSD__, __FreeBSD_kernel__, __darwin__, __NetBSD__ */ 227 | 228 | #define TSOCKS_CLASSA_NET 0xff000000 229 | #define TSOCKS_LOOPBACK_NET 0x7f000000 230 | 231 | /* Loopback addresses. */ 232 | #define TSOCKS_LOOPBACK 0x7f000001 233 | #define TSOCKS_LOOPBACK6 { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } 234 | #define TSOCKS_ANY ((unsigned long int) 0x00000000) 235 | #define TSOCKS_ANY6 { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } 236 | 237 | /* 238 | * Both socket flags here are defined on some BSD and Linux but not on OS X so 239 | * simply nullify them. Include socket.h so the constants are defined before we 240 | * test them. 241 | */ 242 | #include 243 | #ifndef SOCK_CLOEXEC 244 | #define SOCK_CLOEXEC 0 245 | #endif 246 | #ifndef SOCK_NONBLOCK 247 | #define SOCK_NONBLOCK 0 248 | #endif 249 | 250 | /* 251 | * Macro to tell if a given socket type is a SOCK_STREAM or not. The macro 252 | * resolve to 1 if yes else 0. 253 | */ 254 | #if defined(__NetBSD__) 255 | #define IS_SOCK_STREAM(type) \ 256 | ((type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC | SOCK_NOSIGPIPE)) == SOCK_STREAM) 257 | #define IS_SOCK_DGRAM(type) \ 258 | ((type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC | SOCK_NOSIGPIPE)) == SOCK_DGRAM) 259 | #else /* __NetBSD__ */ 260 | #define IS_SOCK_STREAM(type) \ 261 | ((type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC)) == SOCK_STREAM) 262 | #define IS_SOCK_DGRAM(type) \ 263 | ((type & ~(SOCK_NONBLOCK | SOCK_CLOEXEC)) == SOCK_DGRAM) 264 | #endif /* __NetBSD__ */ 265 | 266 | #endif /* TORSOCKS_COMPAT_H */ 267 | -------------------------------------------------------------------------------- /src/common/config-file.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2000-2008 - Shaun Clowes 3 | * 2008-2011 - Robert Hogan 4 | * 2013 - David Goulet 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License, version 2 only, as 8 | * published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 | * more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along with 16 | * this program; if not, write to the Free Software Foundation, Inc., 51 17 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef CONFIG_FILE_H 21 | #define CONFIG_FILE_H 22 | 23 | #include 24 | 25 | #include "connection.h" 26 | #include "socks5.h" 27 | 28 | /* 29 | * Represent the values in a configuration file (torsocks.conf). Basically, 30 | * this is the data structure of a parsed config file. 31 | */ 32 | struct config_file { 33 | /* The tor address is inet or inet 6. */ 34 | enum connection_domain tor_domain; 35 | /* The IP of the Tor SOCKS. */ 36 | char *tor_address; 37 | /* The port of the Tor SOCKS. */ 38 | in_port_t tor_port; 39 | 40 | /* 41 | * Base for onion address pool and the mask. In the config file, this is 42 | * represented by BASE/MASK like so: 127.0.69.0/24 43 | */ 44 | in_addr_t onion_base; 45 | uint8_t onion_mask; 46 | 47 | /* 48 | * Username and password for Tor stream isolation for the SOCKS5 connection 49 | * method. 50 | */ 51 | char socks5_username[SOCKS5_USERNAME_LEN]; 52 | char socks5_password[SOCKS5_PASSWORD_LEN]; 53 | }; 54 | 55 | /* 56 | * Structure representing a complete parsed file. 57 | */ 58 | struct configuration { 59 | /* 60 | * Parsed config file (torsocks.conf). 61 | */ 62 | struct config_file conf_file; 63 | 64 | /* 65 | * Socks5 address so basically where to connect to Tor. 66 | */ 67 | struct connection_addr socks5_addr; 68 | 69 | /* 70 | * Indicate if we should use SOCKS5 authentication. If this value is set, 71 | * both the username and password in the configuration file MUST be 72 | * initialized to something of len > 0. 73 | */ 74 | unsigned int socks5_use_auth:1; 75 | 76 | /* 77 | * Allow inbound connections meaning listen() and accept() are permitted 78 | * for non localhost addresses. 79 | */ 80 | unsigned int allow_inbound:1; 81 | 82 | /* 83 | * Allow outbound connections to localhost that bypass Tor. 84 | */ 85 | unsigned int allow_outbound_localhost; 86 | 87 | /* 88 | * Automatically set the SOCKS5 authentication to a unique per-process 89 | * value. If this value is set, the user MUST NOT have provided a 90 | * username or password. 91 | */ 92 | unsigned int isolate_pid:1; 93 | }; 94 | 95 | int config_file_read(const char *filename, struct configuration *config); 96 | void config_file_destroy(struct config_file *conf); 97 | int conf_file_set_tor_address(const char *addr, struct configuration *config); 98 | int conf_file_set_tor_port(const char *port, struct configuration *config); 99 | int conf_file_set_socks5_pass(const char *password, 100 | struct configuration *config); 101 | int conf_file_set_socks5_user(const char *username, 102 | struct configuration *config); 103 | int conf_file_set_allow_inbound(const char *val, struct configuration *config); 104 | int conf_file_set_allow_outbound_localhost(const char *val, struct 105 | configuration *config); 106 | int conf_file_set_isolate_pid(const char *val, struct configuration *config); 107 | 108 | int conf_apply_socks_auth(struct configuration *config); 109 | 110 | #endif /* CONFIG_FILE_H */ 111 | -------------------------------------------------------------------------------- /src/common/connection.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with 14 | * this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include "connection.h" 23 | #include "macros.h" 24 | 25 | /* 26 | * Connection registry mutex. 27 | * 28 | * MUST be acquired for each read/write operation on the connection registry 29 | * declared below. 30 | * 31 | * This mutex is NOT nested anywhere. 32 | */ 33 | static TSOCKS_INIT_MUTEX(connection_registry_mutex); 34 | 35 | /* 36 | * Release connection using the given refcount located inside the connection 37 | * object. This is ONLY called from the connection put reference. After this 38 | * call, the connection object associated with that refcount object is freed. 39 | */ 40 | static void release_conn(struct ref *ref) 41 | { 42 | struct connection *conn = container_of(ref, struct connection, refcount); 43 | connection_destroy(conn); 44 | } 45 | 46 | /* 47 | * Return 0 if the two connections are equal else 1. 48 | */ 49 | static inline int conn_equal_fct(struct connection *c1, 50 | struct connection *c2) 51 | { 52 | return (c1->fd == c2->fd); 53 | } 54 | 55 | /* 56 | * Return a hash value based on the unique fd of the given connection. 57 | */ 58 | static inline unsigned int conn_hash_fct(struct connection *c) 59 | { 60 | unsigned int mask; 61 | 62 | assert(c); 63 | 64 | switch (sizeof(mask)) { 65 | case 1: 66 | mask = 0xff; 67 | break; 68 | case 2: 69 | mask = 0xffff; 70 | break; 71 | case 4: 72 | default: 73 | mask = 0xffffffff; 74 | break; 75 | } 76 | 77 | return (((unsigned int)(c->fd) << 8) ^ 78 | ((unsigned int)((c->fd >> sizeof(mask)) & mask)) ^ 79 | ((unsigned int)(c->fd & mask))); 80 | } 81 | 82 | /* 83 | * Declare the connection registry. 84 | */ 85 | static HT_HEAD(connection_registry, connection) connection_registry_root = HT_INITIALIZER(); 86 | HT_PROTOTYPE(connection_registry, connection, node, conn_hash_fct, 87 | conn_equal_fct); 88 | HT_GENERATE(connection_registry, connection, node, conn_hash_fct, 89 | conn_equal_fct, 0.5, malloc, realloc, free); 90 | 91 | /* 92 | * Acquire connection registry mutex. 93 | */ 94 | ATTR_HIDDEN 95 | void connection_registry_lock(void) 96 | { 97 | tsocks_mutex_lock(&connection_registry_mutex); 98 | } 99 | 100 | /* 101 | * Release connection registry mutex. 102 | */ 103 | ATTR_HIDDEN 104 | void connection_registry_unlock(void) 105 | { 106 | tsocks_mutex_unlock(&connection_registry_mutex); 107 | } 108 | 109 | /* 110 | * Set an already allocated connection address using the given IPv4/6 address, 111 | * domain and port. 112 | * 113 | * Return 0 on success or else a negative value. 114 | */ 115 | ATTR_HIDDEN 116 | int connection_addr_set(enum connection_domain domain, const char *ip, 117 | in_port_t port, struct connection_addr *addr) 118 | { 119 | int ret; 120 | 121 | assert(ip); 122 | assert(addr); 123 | 124 | if (port == 0) { 125 | ret = -EINVAL; 126 | ERR("Connection addr set port out of range: %d", port); 127 | goto error; 128 | } 129 | 130 | memset(addr, 0, sizeof(*addr)); 131 | 132 | switch (domain) { 133 | case CONNECTION_DOMAIN_INET: 134 | addr->domain = domain; 135 | addr->u.sin.sin_family = AF_INET; 136 | addr->u.sin.sin_port = htons(port); 137 | ret = inet_pton(addr->u.sin.sin_family, ip, 138 | &addr->u.sin.sin_addr); 139 | if (ret != 1) { 140 | PERROR("Connection addr set inet_pton"); 141 | ret = -EINVAL; 142 | goto error; 143 | } 144 | break; 145 | case CONNECTION_DOMAIN_INET6: 146 | addr->domain = domain; 147 | addr->u.sin6.sin6_family = AF_INET6; 148 | addr->u.sin6.sin6_port = htons(port); 149 | ret = inet_pton(addr->u.sin6.sin6_family, ip, 150 | &addr->u.sin6.sin6_addr); 151 | if (ret != 1) { 152 | PERROR("Connection addr6 set inet_pton"); 153 | ret = -EINVAL; 154 | goto error; 155 | } 156 | break; 157 | default: 158 | ERR("Connection addr set unknown domain %d", domain); 159 | ret = -EINVAL; 160 | goto error; 161 | } 162 | 163 | /* Everything is set and good. */ 164 | ret = 0; 165 | 166 | error: 167 | return ret; 168 | } 169 | 170 | /* 171 | * Create a new connection with the given fd and destination address. 172 | * 173 | * Return a newly allocated connection object or else NULL. 174 | */ 175 | ATTR_HIDDEN 176 | struct connection *connection_create(int fd, const struct sockaddr *dest) 177 | { 178 | struct connection *conn = NULL; 179 | 180 | conn = zmalloc(sizeof(*conn)); 181 | if (!conn) { 182 | PERROR("zmalloc connection"); 183 | goto error; 184 | } 185 | 186 | if (dest) { 187 | switch (dest->sa_family) { 188 | case AF_INET: 189 | conn->dest_addr.domain = CONNECTION_DOMAIN_INET; 190 | memcpy(&conn->dest_addr.u.sin, dest, 191 | sizeof(conn->dest_addr.u.sin)); 192 | break; 193 | case AF_INET6: 194 | conn->dest_addr.domain = CONNECTION_DOMAIN_INET6; 195 | memcpy(&conn->dest_addr.u.sin6, dest, 196 | sizeof(conn->dest_addr.u.sin6)); 197 | break; 198 | default: 199 | ERR("Connection domain unknown %d", dest->sa_family); 200 | goto error; 201 | } 202 | } 203 | 204 | conn->fd = fd; 205 | connection_get_ref(conn); 206 | 207 | return conn; 208 | 209 | error: 210 | free(conn); 211 | return NULL; 212 | } 213 | 214 | /* 215 | * Return the matching element with the given key or NULL if not found. 216 | */ 217 | ATTR_HIDDEN 218 | struct connection *connection_find(int key) 219 | { 220 | struct connection c_tmp; 221 | 222 | c_tmp.fd = key; 223 | return HT_FIND(connection_registry, &connection_registry_root, &c_tmp); 224 | } 225 | 226 | /* 227 | * Insert a connection object into the hash table. 228 | */ 229 | ATTR_HIDDEN 230 | void connection_insert(struct connection *conn) 231 | { 232 | struct connection *c_tmp; 233 | 234 | assert(conn); 235 | 236 | /* An existing element is a code flow error. */ 237 | c_tmp = connection_find(conn->fd); 238 | assert(!c_tmp); 239 | 240 | HT_INSERT(connection_registry, &connection_registry_root, conn); 241 | } 242 | 243 | /* 244 | * Remove a given connection object from the registry. 245 | */ 246 | ATTR_HIDDEN 247 | void connection_remove(struct connection *conn) 248 | { 249 | assert(conn); 250 | HT_REMOVE(connection_registry, &connection_registry_root, conn); 251 | } 252 | 253 | /* 254 | * Destroy a connection by freeing its memory. 255 | */ 256 | ATTR_HIDDEN 257 | void connection_destroy(struct connection *conn) 258 | { 259 | if (!conn) { 260 | return; 261 | } 262 | 263 | free(conn->dest_addr.hostname.addr); 264 | free(conn); 265 | } 266 | 267 | /* 268 | * Get a reference of the given connection object. 269 | */ 270 | ATTR_HIDDEN 271 | void connection_get_ref(struct connection *c) 272 | { 273 | ref_get(&c->refcount); 274 | } 275 | 276 | /* 277 | * Put back a reference of the given connection object. If the refcount drops 278 | * to 0, the release connection function is called which frees the object. 279 | */ 280 | ATTR_HIDDEN 281 | void connection_put_ref(struct connection *c) 282 | { 283 | ref_put(&c->refcount, release_conn); 284 | } 285 | -------------------------------------------------------------------------------- /src/common/connection.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with 14 | * this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #ifndef TORSOCKS_CONNECTION_H 19 | #define TORSOCKS_CONNECTION_H 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include "defaults.h" 26 | #include "ht.h" 27 | #include "macros.h" 28 | #include "ref.h" 29 | 30 | enum connection_domain { 31 | CONNECTION_DOMAIN_INET = 1, 32 | CONNECTION_DOMAIN_INET6 = 2, 33 | CONNECTION_DOMAIN_NAME = 3, 34 | }; 35 | 36 | /* 37 | * Connection address which both supports IPv4 and IPv6. 38 | */ 39 | struct connection_addr { 40 | enum connection_domain domain; 41 | 42 | struct { 43 | char *addr; 44 | uint16_t port; 45 | } hostname; 46 | 47 | union { 48 | struct sockaddr_in sin; 49 | struct sockaddr_in6 sin6; 50 | } u; 51 | }; 52 | 53 | /* 54 | * Connection object representing a connect we did to the Tor network from a 55 | * connect(2) hijacked call. 56 | */ 57 | struct connection { 58 | /* Socket fd and also unique ID. */ 59 | int fd; 60 | 61 | /* Remote destination that passes through Tor. */ 62 | struct connection_addr dest_addr; 63 | 64 | /* 65 | * Object refcount needed to access this object outside the registry lock. 66 | * This is always initialized to 1 so only the destroy process can bring 67 | * the refcount to 0 so to delete it. 68 | */ 69 | struct ref refcount; 70 | 71 | /* Hash table node. */ 72 | HT_ENTRY(connection) node; 73 | }; 74 | 75 | int connection_addr_set(enum connection_domain domain, const char *ip, 76 | in_port_t port, struct connection_addr *addr); 77 | 78 | struct connection *connection_create(int fd, const struct sockaddr *dest); 79 | struct connection *connection_find(int key); 80 | void connection_destroy(struct connection *conn); 81 | void connection_remove(struct connection *conn); 82 | void connection_insert(struct connection *conn); 83 | 84 | void connection_registry_lock(void); 85 | void connection_registry_unlock(void); 86 | 87 | void connection_get_ref(struct connection *c); 88 | void connection_put_ref(struct connection *c); 89 | 90 | #endif /* TORSOCKS_CONNECTION_H */ 91 | -------------------------------------------------------------------------------- /src/common/defaults.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with 14 | * this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #ifndef TORSOCKS_DEFAULTS_H 19 | #define TORSOCKS_DEFAULTS_H 20 | 21 | #include "connection.h" 22 | #include "log.h" 23 | 24 | #define DEFAULT_TOR_PORT 9050 25 | #define DEFAULT_TOR_ADDRESS "127.0.0.1" 26 | #define DEFAULT_TOR_DOMAIN CONNECTION_DOMAIN_INET 27 | 28 | /* Logging defaults. */ 29 | #define DEFAULT_LOG_LEVEL_ENV "TORSOCKS_LOG_LEVEL" 30 | #define DEFAULT_LOG_TIME_ENV "TORSOCKS_LOG_TIME" 31 | #define DEFAULT_LOG_FILEPATH_ENV "TORSOCKS_LOG_FILE_PATH" 32 | #define DEFAULT_LOG_TIME_STATUS LOG_TIME_ADD 33 | #define DEFAULT_LOG_LEVEL MSGWARN 34 | 35 | /* 36 | * RFC 1035 specifies a maxium of 255 possibe for domain name. 37 | * (https://www.ietf.org/rfc/rfc1035.txt). 38 | */ 39 | #define DEFAULT_DOMAIN_NAME_SIZE 255 40 | 41 | #define DEFAULT_CONF_FILENAME "torsocks.conf" 42 | #define DEFAULT_CONF_FILE CONFDIR "/tor/" DEFAULT_CONF_FILENAME 43 | #define DEFAULT_CONF_FILE_ENV "TORSOCKS_CONF_FILE" 44 | 45 | /* 46 | * Maximum number of token in a single line of the torsocks configuration file. 47 | * For instance, "TorAddress 127.0.0.1" is two tokens. 48 | */ 49 | #define DEFAULT_MAX_CONF_TOKEN 5 50 | 51 | /* 52 | * Default initial size of the onion pool. 53 | */ 54 | #define DEFAULT_ONION_POOL_SIZE 8 55 | 56 | /* 57 | * The default onion pool cookie range starting at 0 up to 255. 58 | */ 59 | #define DEFAULT_ONION_ADDR_RANGE "127.42.42.0" 60 | #define DEFAULT_ONION_ADDR_MASK "24" 61 | 62 | /* Env. variable for SOCKS5 authentication */ 63 | #define DEFAULT_SOCKS5_USER_ENV "TORSOCKS_USERNAME" 64 | #define DEFAULT_SOCKS5_PASS_ENV "TORSOCKS_PASSWORD" 65 | 66 | /* Env. variable for Tor hostname and port. */ 67 | #define DEFAULT_TOR_ADDRESS_ENV "TORSOCKS_TOR_ADDRESS" 68 | #define DEFAULT_TOR_PORT_ENV "TORSOCKS_TOR_PORT" 69 | 70 | /* Control if torsocks allows inbound connection or not. */ 71 | #define DEFAULT_ALLOW_INBOUND_ENV "TORSOCKS_ALLOW_INBOUND" 72 | 73 | /* Control if torsocks isolates based on PID or not. */ 74 | #define DEFAULT_ISOLATE_PID_ENV "TORSOCKS_ISOLATE_PID" 75 | 76 | #endif /* TORSOCKS_DEFAULTS_H */ 77 | -------------------------------------------------------------------------------- /src/common/log.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with 14 | * this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "defaults.h" 28 | #include "macros.h" 29 | 30 | static struct log_config { 31 | FILE *fp; 32 | char *filepath; 33 | /* Add time or not to the log entry. */ 34 | enum log_time_status time_status; 35 | } logconfig; 36 | 37 | /* 38 | * The default logging level is to only log error messages. 39 | */ 40 | int tsocks_loglevel = DEFAULT_LOG_LEVEL; 41 | 42 | /* 43 | * Add a special formatted timestamp at the beginning of the given buffer. 44 | * 45 | * On success, return the number of bytes written else, return 0. 46 | */ 47 | static size_t add_time_to_log(char *buf, size_t len) 48 | { 49 | time_t now; 50 | 51 | assert(buf); 52 | 53 | /* Get time stamp. */ 54 | time(&now); 55 | return snprintf(buf, len, "%llu ", (unsigned long long)now); 56 | } 57 | 58 | /* 59 | * Log function taking a format and variable number of arguments fitting the 60 | * given format. 61 | */ 62 | static void _log_write(char *buf, size_t len) 63 | { 64 | int ret; 65 | 66 | assert(buf); 67 | assert(logconfig.fp); 68 | 69 | /* Make sure buffer is NULL terminated. */ 70 | buf[len - 1] = '\0'; 71 | 72 | ret = fprintf(logconfig.fp, "%s", buf); 73 | if (ret < 0) { 74 | fprintf(stderr, "[tsocks] logging failed. Stopping logging.\n"); 75 | log_destroy(); 76 | goto end; 77 | } 78 | 79 | /* 80 | * On a write failure we stop the logging but a flush failure is not that 81 | * critical. 82 | */ 83 | (void) fflush(logconfig.fp); 84 | 85 | end: 86 | return; 87 | } 88 | 89 | /* 90 | * Log messages using the logconfig configuration. 91 | */ 92 | ATTR_HIDDEN 93 | void log_print(const char *fmt, ...) 94 | { 95 | int ret; 96 | size_t written = 0; 97 | va_list ap; 98 | /* This is a hard limit for the size of the line. */ 99 | char buf[4096]; 100 | 101 | assert(fmt); 102 | 103 | if (!logconfig.fp) { 104 | goto end; 105 | } 106 | 107 | memset(buf, 0, sizeof(buf)); 108 | va_start(ap, fmt); 109 | 110 | if (logconfig.time_status == LOG_TIME_ADD) { 111 | written = add_time_to_log(buf, sizeof(buf)); 112 | } 113 | 114 | ret = vsnprintf(buf + written, sizeof(buf) - written, fmt, ap); 115 | if (ret < 0) { 116 | perror("[tsocks] vsnprintf log"); 117 | goto error; 118 | } 119 | 120 | _log_write(buf, sizeof(buf)); 121 | 122 | error: 123 | va_end(ap); 124 | end: 125 | return; 126 | } 127 | 128 | /* 129 | * Initialize logconfig. 130 | * 131 | * Return 0 on success or else a negative errno value. 132 | */ 133 | ATTR_HIDDEN 134 | int log_init(int level, const char *filepath, enum log_time_status t_status) 135 | { 136 | int ret = 0; 137 | 138 | /* Reset logconfig. Useful if this is called multiple times. */ 139 | memset(&logconfig, 0, sizeof(logconfig)); 140 | 141 | if (level < MSGNONE || level > MSGDEBUG) { 142 | fprintf(stderr, "[tsocks] Unknown loglevel %d\n", level); 143 | ret = -ENOENT; 144 | goto error; 145 | } 146 | 147 | if (filepath) { 148 | logconfig.filepath = strdup(filepath); 149 | if (!logconfig.filepath) { 150 | perror("[tsocks] log init strdup"); 151 | ret = -errno; 152 | goto error; 153 | } 154 | 155 | logconfig.fp = fopen(filepath, "a"); 156 | if (!logconfig.fp) { 157 | fprintf(stderr, "[tsocks] Unable to open log file %s\n", filepath); 158 | free(logconfig.filepath); 159 | logconfig.filepath = NULL; 160 | ret = -errno; 161 | goto error; 162 | } 163 | setbuf(logconfig.fp, NULL); 164 | } else { 165 | /* The default output is stderr if no filepath is given. */ 166 | ret = fileno(stderr); 167 | if (ret >= 0 && errno != EBADF) { 168 | logconfig.fp = stderr; 169 | ret = 0; 170 | } 171 | } 172 | 173 | tsocks_loglevel = level; 174 | logconfig.time_status = t_status; 175 | 176 | error: 177 | return ret; 178 | } 179 | 180 | /* 181 | * Cleanup the logconfig data structure. 182 | */ 183 | ATTR_HIDDEN 184 | void log_destroy(void) 185 | { 186 | free(logconfig.filepath); 187 | logconfig.filepath = NULL; 188 | 189 | /* Don't call fclose() because torsocks fclose() generates log messages and 190 | * so calling it here could cause a loop. Just zero out the fp so it won't 191 | * be used again. */ 192 | logconfig.fp = NULL; 193 | } 194 | 195 | /* 196 | * Clean up if the fd for the log file gets closed. 197 | */ 198 | ATTR_HIDDEN 199 | void log_fd_close_notify(int fd) 200 | { 201 | if (fd >= 0 && logconfig.fp && (fd == fileno(logconfig.fp))) { 202 | log_destroy(); 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /src/common/log.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2000-2008 - Shaun Clowes 3 | * 2008-2011 - Robert Hogan 4 | * 2013 - David Goulet 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License, version 2 only, as 8 | * published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 | * more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along with 16 | * this program; if not, write to the Free Software Foundation, Inc., 51 17 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef TORSOCKS_LOG_H 21 | #define TORSOCKS_LOG_H 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "compat.h" 29 | 30 | /* Stringify the expansion of a define */ 31 | #define XSTR(d) STR(d) 32 | #define STR(s) #s 33 | 34 | #define MSGNONE 0x1 35 | #define MSGERR 0x2 36 | #define MSGWARN 0x3 37 | #define MSGNOTICE 0x4 38 | #define MSGDEBUG 0x5 39 | 40 | /* 41 | * Used during logging initialization whether or not to add the time or 42 | * suppress it from a log entry. 43 | */ 44 | enum log_time_status { 45 | LOG_TIME_NONE = 0, 46 | LOG_TIME_ADD = 1, 47 | }; 48 | 49 | extern int tsocks_loglevel; 50 | 51 | void log_print(const char *fmt, ...); 52 | int log_init(int level, const char *filepath, enum log_time_status t_status); 53 | void log_destroy(void); 54 | void log_fd_close_notify(int fd); 55 | 56 | #define __tsocks_print(level, fmt, args...) \ 57 | do { \ 58 | if (level != MSGNONE && level <= tsocks_loglevel) { \ 59 | log_print(fmt, ## args); \ 60 | } \ 61 | } while (0) 62 | 63 | #define _ERRMSG(msg, type, fmt, args...) __tsocks_print(type, msg \ 64 | " torsocks[%ld]: " fmt " (in %s() at " __FILE__ ":" XSTR(__LINE__) ")\n", \ 65 | (long) getpid(), ## args, __func__) 66 | 67 | #define MSG(fmt, args...) __tsocks_print(MSGNOTICE, fmt "\n", ## args) 68 | #define ERR(fmt, args...) _ERRMSG("ERROR", MSGERR, fmt, ## args) 69 | #define WARN(fmt, args...) _ERRMSG("WARNING", MSGWARN, fmt, ## args) 70 | #define DBG(fmt, args...) _ERRMSG("DEBUG", MSGDEBUG, fmt, ## args) 71 | 72 | /* 73 | * Local wrapper used by the PERROR() call below. Should NOT be used outside of 74 | * this scope. 75 | */ 76 | #define _PERROR(fmt, args...) _ERRMSG("PERROR", MSGERR, fmt, ## args) 77 | 78 | #if !defined(__linux__) || \ 79 | ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !defined(_GNU_SOURCE)) || \ 80 | !defined(__GLIBC__) 81 | 82 | /* 83 | * Version using XSI strerror_r. 84 | */ 85 | #define PERROR(call, args...) \ 86 | do { \ 87 | char buf[200]; \ 88 | strerror_r(errno, buf, sizeof(buf)); \ 89 | _PERROR(call ": %s", ## args, buf); \ 90 | } while(0); 91 | 92 | #else /* _POSIX_C_SOURCE */ 93 | 94 | /* 95 | * Version using GNU strerror_r, for linux with appropriate defines. 96 | */ 97 | #define PERROR(call, args...) \ 98 | do { \ 99 | char *buf; \ 100 | char tmp[200]; \ 101 | buf = strerror_r(errno, tmp, sizeof(tmp)); \ 102 | _PERROR(call ": %s", ## args, buf); \ 103 | } while(0); 104 | 105 | #endif /* _POSIX_C_SOURCE */ 106 | 107 | #endif /* TORSOCKS_LOG_H */ 108 | -------------------------------------------------------------------------------- /src/common/macros.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 - Mathieu Desnoyers 3 | * 2013 - David Goulet 4 | * 5 | * This program is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License, version 2 only, as 7 | * published by the Free Software Foundation. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 | * more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along with 15 | * this program; if not, write to the Free Software Foundation, Inc., 51 16 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef TORSOCKS_MACROS_H 20 | #define TORSOCKS_MACROS_H 21 | 22 | #include /* for offsetof */ 23 | 24 | /* 25 | * container_of - Get the address of an object containing a field. 26 | * 27 | * @ptr: pointer to the field. 28 | * @type: type of the object. 29 | * @member: name of the field within the object. 30 | */ 31 | #define container_of(ptr, type, member) \ 32 | ({ \ 33 | const __typeof__(((type *) NULL)->member) * __ptr = (ptr); \ 34 | (type *)((char *)__ptr - offsetof(type, member)); \ 35 | }) 36 | 37 | /* Memory allocation zeroed. */ 38 | #define zmalloc(x) calloc(1, x) 39 | 40 | #ifndef ATTR_HIDDEN 41 | #define ATTR_HIDDEN __attribute__((visibility("hidden"))) 42 | #endif 43 | 44 | #ifndef ATTR_UNUSED 45 | #define ATTR_UNUSED __attribute__ ((unused)) 46 | #endif 47 | 48 | #ifndef min 49 | #define min(a, b) ((a) < (b) ? (a) : (b)) 50 | #endif 51 | 52 | #endif /* TORSOCKS_MACROS_H */ 53 | -------------------------------------------------------------------------------- /src/common/onion.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with 14 | * this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #include 19 | 20 | #include "defaults.h" 21 | #include "log.h" 22 | #include "onion.h" 23 | 24 | /* 25 | * Resize pool entries of new_size. 26 | * 27 | * Return 0 on success or else -1. 28 | */ 29 | static int resize_onion_pool(struct onion_pool *pool, uint32_t new_size) 30 | { 31 | struct onion_entry **tmp; 32 | 33 | assert(new_size > pool->size); 34 | 35 | tmp = realloc(pool->entries, new_size * sizeof(*tmp)); 36 | if (!tmp) { 37 | PERROR("[onion] resize onion pool"); 38 | goto error; 39 | } 40 | 41 | DBG("[onion] Onion pool resized from size %lu to new size %lu", pool->size, 42 | new_size); 43 | 44 | pool->entries = tmp; 45 | pool->size = new_size; 46 | return 0; 47 | 48 | error: 49 | return -1; 50 | } 51 | 52 | /* 53 | * Insert an onion entry in the given pool. 54 | * 55 | * Return 0 on success or else a negative value. 56 | */ 57 | static int insert_onion_entry(struct onion_entry *entry, 58 | struct onion_pool *pool) 59 | { 60 | int ret; 61 | 62 | assert(entry); 63 | assert(pool); 64 | 65 | if (pool->count >= pool->size) { 66 | /* Double the size of the pool. */ 67 | ret = resize_onion_pool(pool, pool->size * 2); 68 | if (ret < 0) { 69 | goto error; 70 | } 71 | } 72 | 73 | pool->entries[pool->next_entry_pos] = entry; 74 | pool->next_entry_pos++; 75 | pool->count++; 76 | ret = 0; 77 | 78 | DBG("[onion] Entry added to the onion pool at index %lu", 79 | pool->next_entry_pos - 1); 80 | 81 | error: 82 | return ret; 83 | } 84 | 85 | /* 86 | * Initialize an already allocated onion pool using the given values. 87 | * 88 | * Return 0 on success or else a negative value. 89 | */ 90 | ATTR_HIDDEN 91 | int onion_pool_init(struct onion_pool *pool, in_addr_t addr, uint8_t mask) 92 | { 93 | int ret = 0; 94 | 95 | assert(pool); 96 | 97 | if (mask == 0 || mask > 32) { 98 | ERR("[onion] Pool initialized with mask set to %u.", mask); 99 | ret = -EINVAL; 100 | goto error; 101 | } 102 | 103 | DBG("[onion] Pool init with subnet %s and mask %u", 104 | inet_ntoa(*((struct in_addr *) &addr)), mask); 105 | 106 | /* 107 | * Get base of subnet. For example, 127.0.0.68/27 will set the base to 64 108 | * and the max_pos to 95. 109 | */ 110 | pool->base = (((ntohl(addr) >> (32 - mask)) << (32 - mask)) << 24) >> 24; 111 | pool->max_pos = pool->base + ((1UL << (32 - mask)) - 1); 112 | pool->next_entry_pos = 0; 113 | pool->count = 0; 114 | tsocks_mutex_init(&pool->lock); 115 | 116 | /* 117 | * Get the minimum value between the two to avoid allocating more memory 118 | * than we need. 119 | */ 120 | pool->size = min(DEFAULT_ONION_POOL_SIZE, (pool->max_pos - pool->base) + 1); 121 | 122 | memcpy(&pool->ip_subnet, &addr, sizeof(pool->ip_subnet)); 123 | 124 | pool->entries = zmalloc(sizeof(struct onion_entry *) * pool->size); 125 | if (!pool->entries) { 126 | PERROR("[onion] zmalloc pool init"); 127 | ret = -ENOMEM; 128 | goto error; 129 | } 130 | 131 | DBG("[onion] Pool initialized with base %lu, max_pos %lu and size %lu", 132 | pool->base, pool->max_pos, pool->size); 133 | 134 | error: 135 | return ret; 136 | } 137 | 138 | /* 139 | * Destroy onion pool by freeing every entry. 140 | */ 141 | ATTR_HIDDEN 142 | void onion_pool_destroy(struct onion_pool *pool) 143 | { 144 | uint32_t i; 145 | 146 | assert(pool); 147 | 148 | DBG("[onion] Destroying onion pool containing %u entry", pool->count); 149 | 150 | for (i = 0; i < pool->count; i++) { 151 | onion_entry_destroy(pool->entries[i]); 152 | } 153 | 154 | free(pool->entries); 155 | } 156 | 157 | /* 158 | * Allocate an onion entry object and return the pointer. This MUST be called 159 | * with the onion pool lock acquired. 160 | * 161 | * Return a newly allocated onion entry or else NULL. 162 | */ 163 | ATTR_HIDDEN 164 | struct onion_entry *onion_entry_create(struct onion_pool *pool, 165 | const char *onion_name) 166 | { 167 | int ret; 168 | uint32_t ip_host_order; 169 | struct onion_entry *entry = NULL; 170 | 171 | assert(pool); 172 | assert(onion_name); 173 | 174 | DBG("[onion] Creating onion entry for name %s", onion_name); 175 | 176 | if (pool->next_entry_pos == pool->max_pos) { 177 | ERR("[onion] Can't create anymore onion entry. Maximum reached (%u)", 178 | pool->max_pos); 179 | goto error; 180 | } 181 | 182 | entry = zmalloc(sizeof(struct onion_entry)); 183 | if (!entry) { 184 | PERROR("[onion] zmalloc entry"); 185 | goto error; 186 | } 187 | 188 | /* Copy hostname and force NULL byte at the end. */ 189 | strncpy(entry->hostname, onion_name, sizeof(entry->hostname)); 190 | entry->hostname[sizeof(entry->hostname) - 1] = '\0'; 191 | 192 | /* 193 | * Create the new IP from the onion pool which will be the cookie returned 194 | * to the caller. 195 | */ 196 | ip_host_order = ntohl(pool->ip_subnet) + pool->next_entry_pos; 197 | entry->ip = htonl(ip_host_order); 198 | 199 | ret = insert_onion_entry(entry, pool); 200 | if (ret < 0) { 201 | onion_entry_destroy(entry); 202 | entry = NULL; 203 | goto error; 204 | } 205 | 206 | DBG("[onion] Entry added with IP address %s used as cookie", 207 | inet_ntoa(*((struct in_addr *) &entry->ip))); 208 | 209 | error: 210 | return entry; 211 | } 212 | 213 | /* 214 | * Find an onion entry by onion address name. The pool lock MUST be acquired 215 | * before calling this. 216 | * 217 | * Return entry on success or else NULL. 218 | */ 219 | ATTR_HIDDEN 220 | struct onion_entry *onion_entry_find_by_name(const char *onion_name, 221 | struct onion_pool *pool) 222 | { 223 | uint32_t i; 224 | struct onion_entry *entry = NULL; 225 | 226 | assert(onion_name); 227 | assert(pool); 228 | 229 | DBG("[onion] Finding onion entry for name %s", onion_name); 230 | 231 | for (i = 0; i < pool->count; i++) { 232 | if (strcmp(onion_name, pool->entries[i]->hostname) == 0) { 233 | entry = pool->entries[i]; 234 | DBG("[onion] Onion entry name %s found in pool.", 235 | entry->hostname); 236 | goto end; 237 | } 238 | } 239 | 240 | end: 241 | return entry; 242 | } 243 | 244 | /* 245 | * Find an onion entry by IP cookie. The pool lock MUST be acquired before 246 | * calling this. 247 | * 248 | * Return entry on success or else NULL. 249 | */ 250 | ATTR_HIDDEN 251 | struct onion_entry *onion_entry_find_by_addr(const struct sockaddr *sa, 252 | struct onion_pool *pool) 253 | { 254 | uint32_t i; 255 | struct onion_entry *entry = NULL; 256 | const struct sockaddr_in *sin; 257 | 258 | assert(sa); 259 | 260 | /* Onion cookie are only IPv4. */ 261 | if (sa->sa_family == AF_INET6) { 262 | goto end; 263 | } 264 | 265 | sin = (const struct sockaddr_in *) sa; 266 | 267 | DBG("[onion] Finding onion entry for IP %s", 268 | inet_ntoa((*((struct in_addr *) &sin->sin_addr.s_addr)))); 269 | 270 | /* 271 | * XXX: This can be improved by simply getting the offset of the IP with 272 | * the pool subnet which gives the index in the pool entries. For instance, 273 | * 127.0.0.45 with a ip_subnet set to 127.0.0.0/24, the index in the pool 274 | * entries is 45. 275 | */ 276 | for (i = 0; i < pool->count; i++) { 277 | if (pool->entries[i]->ip == sin->sin_addr.s_addr) { 278 | entry = pool->entries[i]; 279 | DBG("[onion] Onion entry name %s found in pool.", 280 | entry->hostname); 281 | goto end; 282 | } 283 | } 284 | 285 | end: 286 | return entry; 287 | } 288 | -------------------------------------------------------------------------------- /src/common/onion.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with 14 | * this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #ifndef TORSOCKS_ONION_H 19 | #define TORSOCKS_ONION_H 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include "compat.h" 26 | #include "macros.h" /* zmalloc */ 27 | 28 | /* 29 | * Onion entry in the pool. This is to map a cookie IP to an .onion address in 30 | * the connect() process. 31 | */ 32 | struct onion_entry { 33 | /* 34 | * It's always an IPv4 which is taken from the onion IP range. 35 | */ 36 | in_addr_t ip; 37 | 38 | /* 39 | * Maximum host name length plus one for the NULL terminated byte. 40 | */ 41 | char hostname[256]; 42 | }; 43 | 44 | /* 45 | * For .onion address representing an address to a hidden service, a "cookie" 46 | * is used during DNS resolution which represents a specific dead IP address 47 | * that is not routable on the Internet. This cookie is returned to the caller 48 | * and once a connect arrives with an address being a cookie, the connection to 49 | * Tor is done using the corresponding onion address. 50 | * 51 | * This object MUST be accessed and modified inside the torsocks registry lock 52 | * to avoid cookie allocation race. Once an entry object reference is acquired, 53 | * the lock can be released since the object is immutable. 54 | */ 55 | struct onion_pool { 56 | /* 57 | * Subnet used for the cookie address. 58 | */ 59 | in_addr_t ip_subnet; 60 | 61 | /* 62 | * Protects every lookup and insertion in this pool object. 63 | * 64 | * This is nested INSIDE the connection registry lock. 65 | */ 66 | tsocks_mutex_t lock; 67 | 68 | /* Number of valid entry in the pool. */ 69 | uint32_t count; 70 | 71 | /* 72 | * Starting base of available cookie. For a range of 127.0.69.64/26, this 73 | * base value would be 64 and the max value in this case is 127. 74 | * 75 | * If the maxium value is reached, the DNS resolution will fail thus never 76 | * returning any cookie to the caller. 77 | */ 78 | uint32_t base; 79 | uint32_t max_pos; 80 | 81 | /* 82 | * Current size of the array. This is the number of allocated entry in the 83 | * pool which does not represent the number of entry. 84 | */ 85 | uint32_t size; 86 | 87 | /* 88 | * This is the next available entry position. Once the onion entry is added 89 | * to the pool, this counter is incremented. If the pool needs to be 90 | * resized, a reallocation is done and size is updated accordingly. 91 | */ 92 | uint32_t next_entry_pos; 93 | 94 | /* 95 | * Array of onion entry indexed by cookie position. For instance, using the 96 | * IP range 127.0.69.0/24, the array is of maximum size 255 and address 97 | * 127.0.69.32 points to the 32th position in the array. 98 | */ 99 | struct onion_entry **entries; 100 | }; 101 | 102 | /* 103 | * Destroy an onion entry object. 104 | */ 105 | static inline void onion_entry_destroy(struct onion_entry *entry) 106 | { 107 | free(entry); 108 | } 109 | 110 | /* Onion entry family functions. */ 111 | struct onion_entry *onion_entry_create(struct onion_pool *pool, 112 | const char *onion_name); 113 | struct onion_entry *onion_entry_find_by_name(const char *onion_name, 114 | struct onion_pool *pool); 115 | struct onion_entry *onion_entry_find_by_addr(const struct sockaddr *sa, 116 | struct onion_pool *pool); 117 | 118 | static inline void onion_pool_lock(struct onion_pool *pool) 119 | { 120 | tsocks_mutex_lock(&pool->lock); 121 | } 122 | 123 | static inline void onion_pool_unlock(struct onion_pool *pool) 124 | { 125 | tsocks_mutex_unlock(&pool->lock); 126 | } 127 | 128 | /* 129 | * Onion pool function calls. 130 | */ 131 | int onion_pool_init(struct onion_pool *pool, in_addr_t base, uint8_t mask); 132 | void onion_pool_destroy(struct onion_pool *pool); 133 | 134 | #endif /* TORSOCKS_ONION_H */ 135 | -------------------------------------------------------------------------------- /src/common/ref.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with 14 | * this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #ifndef TORSOCKS_REF_H 19 | #define TORSOCKS_REF_H 20 | 21 | #include 22 | 23 | #include "compat.h" 24 | 25 | struct ref { 26 | long count; 27 | }; 28 | 29 | #if (defined(__linux__) || defined(__GLIBC__) || defined(__FreeBSD__) || \ 30 | defined(__darwin__) || defined(__NetBSD__)) 31 | 32 | /* 33 | * Get a reference by incrementing the refcount. 34 | */ 35 | static inline void ref_get(struct ref *r) 36 | { 37 | (void) __sync_add_and_fetch(&r->count, 1); 38 | } 39 | 40 | /* 41 | * Put a reference back by decrementing the refcount. 42 | * 43 | * The release function MUST use container_of to get back the object pointer in 44 | * which the ref structure is located. 45 | */ 46 | static inline void ref_put(struct ref *r, 47 | void (*release)(struct ref *)) 48 | { 49 | long ret; 50 | 51 | assert(release); 52 | ret = __sync_sub_and_fetch(&r->count, 1); 53 | assert(ret >= 0); 54 | if (ret == 0) { 55 | release(r); 56 | } 57 | } 58 | 59 | #else 60 | #error "OS not supported" 61 | #endif /* __linux__, __GLIBC__, __FreeBSD__, __darwin__, __NetBSD__ */ 62 | 63 | #endif /* TORSOCKS_REF_H */ 64 | -------------------------------------------------------------------------------- /src/common/socks5.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Structure used by torsocks to form SOCKS requests. 3 | * 4 | * Copyright (C) 2013 - David Goulet 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License, version 2 only, as 8 | * published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 | * more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along with 16 | * this program; if not, write to the Free Software Foundation, Inc., 51 17 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef TORSOCKS_SOCKS_H 21 | #define TORSOCKS_SOCKS_H 22 | 23 | #include 24 | 25 | #include "connection.h" 26 | 27 | /* For SOCKS version 5. */ 28 | #define SOCKS5_VERSION 0x05 29 | 30 | /* 31 | * As stated in the SOCKS extension of Tor, for v5 the "NO AUTHENTICATION 32 | * METHOD" [00] is supported and should be used. 33 | */ 34 | #define SOCKS5_NO_AUTH_METHOD 0x00 35 | #define SOCKS5_USER_PASS_METHOD 0x02 36 | #define SOCKS5_NO_ACCPT_METHOD 0xFF 37 | 38 | /* SOCKS5 rfc1929 username and password authentication. */ 39 | #define SOCKS5_USER_PASS_VER 0x01 40 | 41 | /* Request command. */ 42 | #define SOCKS5_CMD_CONNECT 0x01 43 | #define SOCKS5_CMD_RESOLVE 0xF0 44 | #define SOCKS5_CMD_RESOLVE_PTR 0xF1 45 | 46 | /* Address type. */ 47 | #define SOCKS5_ATYP_IPV4 0x01 48 | #define SOCKS5_ATYP_DOMAIN 0x03 49 | #define SOCKS5_ATYP_IPV6 0x04 50 | 51 | /* Replies code. */ 52 | #define SOCKS5_REPLY_SUCCESS 0x00 53 | #define SOCKS5_REPLY_FAIL 0x01 54 | #define SOCKS5_REPLY_DENY_RULE 0x02 55 | #define SOCKS5_REPLY_NO_NET 0x03 56 | #define SOCKS5_REPLY_NO_HOST 0x04 57 | #define SOCKS5_REPLY_REFUSED 0x05 58 | #define SOCKS5_REPLY_TTL_EXP 0x06 59 | #define SOCKS5_REPLY_CMD_NOTSUP 0x07 60 | #define SOCKS5_REPLY_ADR_NOTSUP 0x08 61 | 62 | /* As described in rfc1929. */ 63 | #define SOCKS5_USERNAME_LEN 255 64 | #define SOCKS5_PASSWORD_LEN 255 65 | 66 | /* Request data structure for the method. */ 67 | struct socks5_method_req { 68 | uint8_t ver; 69 | uint8_t nmethods; 70 | uint8_t methods; 71 | }; 72 | 73 | /* Reply data structure for the method. */ 74 | struct socks5_method_res { 75 | uint8_t ver; 76 | uint8_t method; 77 | }; 78 | 79 | /* First part of a request. */ 80 | struct socks5_request { 81 | uint8_t ver; 82 | uint8_t cmd; 83 | uint8_t rsv; 84 | uint8_t atyp; 85 | }; 86 | 87 | /* IPv4 destination addr for a request. */ 88 | struct socks5_request_ipv4 { 89 | uint8_t addr[4]; 90 | uint16_t port; 91 | }; 92 | 93 | /* IPv6 destination addr for a request. */ 94 | struct socks5_request_ipv6 { 95 | uint8_t addr[16]; 96 | uint16_t port; 97 | }; 98 | 99 | /* Domain name for a request. */ 100 | struct socks5_request_domain { 101 | uint8_t len; 102 | /* Maximum size of len above. No NULL byte is needed. */ 103 | unsigned char name[UINT8_MAX]; 104 | uint16_t port; 105 | }; 106 | 107 | /* Use for the Tor resolve command. */ 108 | struct socks5_request_resolve { 109 | uint8_t len; 110 | unsigned char name[UINT8_MAX]; 111 | uint16_t port; 112 | }; 113 | 114 | /* Use for the Tor resolve ptr command. */ 115 | struct socks5_request_resolve_ptr { 116 | union { 117 | uint8_t ipv4[4]; 118 | uint8_t ipv6[16]; 119 | } addr; 120 | uint16_t port; 121 | }; 122 | 123 | /* Non variable part of a reply. */ 124 | struct socks5_reply { 125 | uint8_t ver; 126 | uint8_t rep; 127 | uint8_t rsv; 128 | uint8_t atyp; 129 | }; 130 | 131 | /* Username/password reply message. */ 132 | struct socks5_user_pass_reply { 133 | uint8_t ver; 134 | uint8_t status; 135 | }; 136 | 137 | int socks5_connect(struct connection *conn); 138 | 139 | /* Method messaging. */ 140 | int socks5_send_method(struct connection *conn, uint8_t type); 141 | int socks5_recv_method(struct connection *conn); 142 | 143 | /* Username/Password request. */ 144 | int socks5_send_user_pass_request(struct connection *conn, 145 | const char *user, const char *pass); 146 | int socks5_recv_user_pass_reply(struct connection *conn); 147 | 148 | /* Connect request. */ 149 | int socks5_send_connect_request(struct connection *conn); 150 | int socks5_recv_connect_reply(struct connection *conn); 151 | 152 | /* Tor DNS resolve. */ 153 | int socks5_send_resolve_request(const char *hostname, struct connection *conn); 154 | int socks5_recv_resolve_reply(struct connection *conn, void *addr, 155 | size_t addrlent); 156 | int socks5_recv_resolve_ptr_reply(struct connection *conn, char **_hostname); 157 | int socks5_send_resolve_ptr_request(struct connection *conn, const void *ip, int af); 158 | 159 | void socks5_init(ssize_t (*new_send_data)(int, const void *, size_t), 160 | ssize_t (*new_recv_data)(int, void *, size_t)); 161 | 162 | #endif /* TORSOCKS_SOCKS_H */ 163 | -------------------------------------------------------------------------------- /src/common/utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2000-2008 - Shaun Clowes 3 | * 2008-2011 - Robert Hogan 4 | * 2013 - David Goulet 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License, version 2 only, as 8 | * published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 | * more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along with 16 | * this program; if not, write to the Free Software Foundation, Inc., 51 17 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "compat.h" 30 | #include "macros.h" 31 | #include "utils.h" 32 | 33 | /* 34 | * Hardcoded list of localhost hostname. In order to resolve these for an 35 | * application, usually we would need to check in /etc/hosts by using 36 | * gethostent() but in order to avoid DNS resolution outside of Tor (even local 37 | * file), only the localhost is resolved and the rest is sent through Tor. 38 | */ 39 | static const char *localhost_names_v4[] = { 40 | "localhost", "ip-localhost", NULL, 41 | }; 42 | 43 | static const char *localhost_names_v6[] = { 44 | "localhost", "ip6-loopback", "ip6-localhost", NULL, 45 | }; 46 | 47 | /* 48 | * Return 1 if the given IP belongs in the af domain else return 0 if the 49 | * given ip is not a valid address or the af value is unknown. 50 | */ 51 | static int check_addr(const char *ip, int af) 52 | { 53 | int ret = 0; 54 | char buf[128]; 55 | 56 | assert(ip); 57 | 58 | ret = inet_pton(af, ip, buf); 59 | if (ret == -1) { 60 | /* Possible if the af value is unknown to inet_pton. */ 61 | ret = 0; 62 | } 63 | 64 | return ret; 65 | } 66 | 67 | /* 68 | * Given a name string and a list NULL terminated of strings, this will try to 69 | * match the name. 70 | * 71 | * Return the entry in the list if match else NULL. 72 | */ 73 | static const char *match_name(const char *name, const char **list) 74 | { 75 | unsigned int count = 0; 76 | const char *entry; 77 | 78 | assert(name); 79 | assert(list); 80 | 81 | while ((entry = list[count]) != NULL) { 82 | int ret; 83 | 84 | ret = strcmp(entry, name); 85 | if (!ret) { 86 | /* Match. */ 87 | goto end; 88 | } 89 | count++; 90 | } 91 | 92 | end: 93 | return entry; 94 | } 95 | 96 | /* 97 | * Return 1 if the given IP is an IPv4. 98 | */ 99 | ATTR_HIDDEN 100 | int utils_is_address_ipv4(const char *ip) 101 | { 102 | return check_addr(ip, AF_INET); 103 | } 104 | 105 | /* 106 | * Return 1 if the given IP is an IPv6. 107 | */ 108 | ATTR_HIDDEN 109 | int utils_is_address_ipv6(const char *ip) 110 | { 111 | return check_addr(ip, AF_INET6); 112 | } 113 | 114 | /* 115 | * This routine breaks up input lines into tokens and places these tokens into 116 | * the array specified by tokens. 117 | * 118 | * Return the number of tokens plus one set in the given array. 119 | */ 120 | ATTR_HIDDEN 121 | int utils_tokenize_ignore_comments(const char *_line, size_t size, char **tokens) 122 | { 123 | int ret, i = 0; 124 | char *c, *line = NULL, *saveptr; 125 | 126 | assert(_line); 127 | assert(tokens); 128 | assert(size <= INT_MAX); 129 | 130 | line = strdup(_line); 131 | if (!line) { 132 | ret = -ENOMEM; 133 | goto error; 134 | } 135 | 136 | /* Ignore line if it starts with a # meaning a comment. */ 137 | if (*line == '#') { 138 | goto end; 139 | } 140 | 141 | c = strtok_r(line, " \t", &saveptr); 142 | while (c != NULL) { 143 | if ((size_t) i >= size) { 144 | ret = -ENOMEM; 145 | goto error; 146 | } 147 | tokens[i] = strdup(c); 148 | if (!tokens[i]) { 149 | ret = -ENOMEM; 150 | goto error; 151 | } 152 | c = strtok_r(NULL, " \t", &saveptr); 153 | i++; 154 | } 155 | 156 | end: 157 | ret = i; 158 | free(line); 159 | return ret; 160 | 161 | error: 162 | free(line); 163 | while (i-- > 0) { 164 | free(tokens[i]); 165 | } 166 | return ret; 167 | } 168 | 169 | /* 170 | * This function is very much like strsep, it looks in a string for a character 171 | * from a list of characters, when it finds one it replaces it with a \0 and 172 | * returns the start of the string (basically spitting out tokens with 173 | * arbitrary separators). 174 | * 175 | * If no match is found the remainder of the string is returned and the start 176 | * pointer is set to be NULL. The difference between standard strsep and this 177 | * function is that this one will set separator to the character separator 178 | * found if it isn't NULL. 179 | */ 180 | ATTR_HIDDEN 181 | char *utils_strsplit(char *separator, char **text, const char *search) 182 | { 183 | unsigned int len; 184 | char *ret; 185 | 186 | ret = *text; 187 | 188 | if (*text == NULL) { 189 | if (separator) { 190 | *separator = '\0'; 191 | } 192 | return NULL; 193 | } 194 | 195 | len = strcspn(*text, search); 196 | if (len == strlen(*text)) { 197 | if (separator) { 198 | *separator = '\0'; 199 | } 200 | *text = NULL; 201 | } else { 202 | *text = *text + len; 203 | if (separator) { 204 | *separator = **text; 205 | } 206 | **text = '\0'; 207 | *text = *text + 1; 208 | } 209 | 210 | return ret; 211 | } 212 | 213 | /* 214 | * Compares the last strlen(s2) characters of s1 with s2. 215 | * 216 | * Returns as for strcasecmp. 217 | */ 218 | ATTR_HIDDEN 219 | int utils_strcasecmpend(const char *s1, const char *s2) 220 | { 221 | size_t n1 = strlen(s1), n2 = strlen(s2); 222 | 223 | if (n2 > n1) { 224 | /* Then they can't be the same; figure out which is bigger */ 225 | return strcasecmp(s1, s2); 226 | } else { 227 | return strncasecmp(s1 + (n1 - n2), s2, n2); 228 | } 229 | } 230 | 231 | /* 232 | * Return 1 if the given sockaddr is localhost else 0 233 | */ 234 | ATTR_HIDDEN 235 | int utils_sockaddr_is_localhost(const struct sockaddr *sa) 236 | { 237 | int is_localhost; 238 | 239 | assert(sa); 240 | 241 | if (sa->sa_family == AF_INET) { 242 | const struct sockaddr_in *sin = (const struct sockaddr_in *) sa; 243 | is_localhost = ((ntohl(sin->sin_addr.s_addr) & TSOCKS_CLASSA_NET) == 244 | TSOCKS_LOOPBACK_NET); 245 | } else if (sa->sa_family == AF_INET6) { 246 | const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *) sa; 247 | static const uint8_t addr[] = TSOCKS_LOOPBACK6; 248 | is_localhost = !memcmp(sin6->sin6_addr.s6_addr, addr, 249 | sizeof(sin6->sin6_addr.s6_addr)); 250 | } else { 251 | /* Unknown sockaddr family thus not localhost. */ 252 | is_localhost = 0; 253 | } 254 | 255 | return is_localhost; 256 | } 257 | 258 | /* 259 | * Try to match a given name to localhost names (v4 and v6). 260 | * 261 | * If a match is found, the address in network byte order is copied in the 262 | * buffer thus len must match the size of the given address family and 1 is 263 | * returned. 264 | * 265 | * If NO match is found, 0 is return and buf is untouched. 266 | * 267 | * If len is the wrong size, -EINVAL is returned and buf is untouched. 268 | */ 269 | ATTR_HIDDEN 270 | int utils_localhost_resolve(const char *name, int af, void *buf, size_t len) 271 | { 272 | const char *entry; 273 | 274 | assert(name); 275 | assert(buf); 276 | 277 | if (af == AF_INET) { 278 | const in_addr_t addr = htonl(TSOCKS_LOOPBACK); 279 | 280 | entry = match_name(name, localhost_names_v4); 281 | if (entry) { 282 | if (len < sizeof(in_addr_t)) { 283 | /* Size of buffer is not large enough. */ 284 | goto error; 285 | } 286 | memcpy(buf, &addr, sizeof(addr)); 287 | goto match; 288 | } 289 | } else if (af == AF_INET6) { 290 | const uint8_t addr[] = TSOCKS_LOOPBACK6; 291 | 292 | entry = match_name(name, localhost_names_v6); 293 | if (entry) { 294 | if (len < sizeof(addr)) { 295 | /* Size of buffer is not large enough. */ 296 | goto error; 297 | } 298 | memcpy(buf, addr, sizeof(addr)); 299 | goto match; 300 | } 301 | } else { 302 | /* Unknown family type. */ 303 | assert(0); 304 | goto error; 305 | } 306 | 307 | /* No match. */ 308 | return 0; 309 | match: 310 | /* Match found. */ 311 | return 1; 312 | error: 313 | return -EINVAL; 314 | } 315 | 316 | /* 317 | * For a given sockaddr, check if the IP address is ANY which is 0.0.0.0 for 318 | * IPv4 and :: for IPv6. 319 | * 320 | * Return 1 if it is else 0. 321 | */ 322 | ATTR_HIDDEN 323 | int utils_is_addr_any(const struct sockaddr *sa) 324 | { 325 | int ret; 326 | 327 | assert(sa); 328 | 329 | if (sa->sa_family == AF_INET) { 330 | const struct sockaddr_in *sin = (const struct sockaddr_in *) sa; 331 | ret = (sin->sin_addr.s_addr == TSOCKS_ANY); 332 | } else if (sa->sa_family == AF_INET6) { 333 | const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *) sa; 334 | const uint8_t addr[] = TSOCKS_ANY6; 335 | ret = !memcmp(sin6->sin6_addr.s6_addr, addr, 336 | sizeof(sin6->sin6_addr.s6_addr)); 337 | } else { 338 | ret = 0; 339 | goto end; 340 | } 341 | 342 | end: 343 | return ret; 344 | } 345 | 346 | /* 347 | * For a given sockaddr, return the port value considering the address family 348 | * structure. 349 | * 350 | * Return the port number in the sockaddr sa or -1 is family is not unknown. 351 | */ 352 | ATTR_HIDDEN 353 | int utils_get_port_from_addr(const struct sockaddr *sa) 354 | { 355 | int port; 356 | 357 | assert(sa); 358 | 359 | if (sa->sa_family == AF_INET) { 360 | port = ((const struct sockaddr_in *) sa)->sin_port; 361 | } else if (sa->sa_family == AF_INET6) { 362 | port = ((const struct sockaddr_in6 *) sa)->sin6_port; 363 | } else { 364 | port = -1; 365 | } 366 | 367 | return port; 368 | } 369 | 370 | /* 371 | * For a given sockaddr, return a const pointer to the address data structure. 372 | * Return NULL if family is not IPv4 or IPv6. 373 | */ 374 | ATTR_HIDDEN 375 | const char *utils_get_addr_from_sockaddr(const struct sockaddr *sa) 376 | { 377 | static char buf[256]; 378 | const void *addrp; 379 | 380 | assert(sa); 381 | 382 | memset(buf, 0, sizeof(buf)); 383 | 384 | if (sa->sa_family == AF_INET) { 385 | addrp = &((const struct sockaddr_in *) sa)->sin_addr; 386 | } else if (sa->sa_family == AF_INET6) { 387 | addrp = &((const struct sockaddr_in6 *) sa)->sin6_addr; 388 | } else { 389 | goto end; 390 | } 391 | 392 | inet_ntop(sa->sa_family, addrp, buf, sizeof(buf)); 393 | 394 | end: 395 | return buf; 396 | } 397 | -------------------------------------------------------------------------------- /src/common/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2000-2008 - Shaun Clowes 3 | * 2008-2011 - Robert Hogan 4 | * 2013 - David Goulet 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License, version 2 only, as 8 | * published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 | * more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along with 16 | * this program; if not, write to the Free Software Foundation, Inc., 51 17 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef TORSOCKS_UTILS_H 21 | #define TORSOCKS_UTILS_H 22 | 23 | #include 24 | 25 | #include "compat.h" 26 | 27 | char *utils_strsplit(char *separator, char **text, const char *search); 28 | int utils_strcasecmpend(const char *s1, const char *s2); 29 | int utils_tokenize_ignore_comments(const char *_line, size_t size, char **tokens); 30 | 31 | int utils_is_address_ipv4(const char *ip); 32 | int utils_is_address_ipv6(const char *ip); 33 | int utils_sockaddr_is_localhost(const struct sockaddr *sa); 34 | int utils_localhost_resolve(const char *name, int af, void *buf, size_t len); 35 | int utils_is_addr_any(const struct sockaddr *sa); 36 | int utils_get_port_from_addr(const struct sockaddr *sa); 37 | const char *utils_get_addr_from_sockaddr(const struct sockaddr *sa); 38 | 39 | #endif /* TORSOCKS_UTILS_H */ 40 | -------------------------------------------------------------------------------- /src/lib/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src -I$(builddir) 2 | #AM_CFLAGS = -fno-strict-aliasing 3 | 4 | libdir = @libdir@/torsocks 5 | 6 | # Install invocation scripts 7 | lib_LTLIBRARIES = libtorsocks.la 8 | 9 | libtorsocks_la_SOURCES = torsocks.c torsocks.h \ 10 | connect.c gethostbyname.c getaddrinfo.c close.c \ 11 | getpeername.c socket.c syscall.c socketpair.c recv.c \ 12 | exit.c accept.c listen.c fclose.c sendto.c execve.c 13 | 14 | libtorsocks_la_LIBADD = $(top_builddir)/src/common/libcommon.la 15 | -------------------------------------------------------------------------------- /src/lib/accept.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with 14 | * this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #include 19 | 20 | #include 21 | 22 | #include "torsocks.h" 23 | 24 | TSOCKS_LIBC_DECL(accept, LIBC_ACCEPT_RET_TYPE, LIBC_ACCEPT_SIG) 25 | 26 | /* 27 | * Torsocks call for accept(2). 28 | */ 29 | LIBC_ACCEPT_RET_TYPE tsocks_accept(LIBC_ACCEPT_SIG) 30 | { 31 | int ret; 32 | socklen_t sa_len; 33 | struct sockaddr sa; 34 | 35 | if (tsocks_config.allow_inbound) { 36 | /* Allowed by the user so directly go to the libc. */ 37 | goto libc_call; 38 | } 39 | 40 | sa_len = sizeof(sa); 41 | 42 | ret = getsockname(sockfd, &sa, &sa_len); 43 | if (ret < 0) { 44 | PERROR("[accept] getsockname"); 45 | goto error; 46 | } 47 | 48 | /* 49 | * accept() on a Unix socket is allowed else we are going to try to match 50 | * it on INET localhost socket. 51 | */ 52 | if (sa.sa_family == AF_UNIX) { 53 | goto libc_call; 54 | } 55 | 56 | /* Inbound localhost connections are allowed. */ 57 | ret = utils_sockaddr_is_localhost(&sa); 58 | if (!ret) { 59 | /* 60 | * Accept is completely denied here since this means that the 61 | * application can accept inbound connections on non localhost that 62 | * are obviously NOT handled by the Tor network thus reject this call. 63 | */ 64 | DBG("[accept] Non localhost inbound connection are not allowed."); 65 | errno = EPERM; 66 | goto error; 67 | } 68 | 69 | libc_call: 70 | return tsocks_libc_accept(LIBC_ACCEPT_ARGS); 71 | 72 | error: 73 | return -1; 74 | } 75 | 76 | /* 77 | * Libc hijacked symbol accept(2). 78 | */ 79 | LIBC_ACCEPT_DECL 80 | { 81 | if (!tsocks_libc_accept) { 82 | tsocks_initialize(); 83 | tsocks_libc_accept = tsocks_find_libc_symbol( 84 | LIBC_ACCEPT_NAME_STR, TSOCKS_SYM_EXIT_NOT_FOUND); 85 | } 86 | 87 | return tsocks_accept(LIBC_ACCEPT_ARGS); 88 | } 89 | 90 | #if (defined(__linux__)) 91 | 92 | TSOCKS_LIBC_DECL(accept4, LIBC_ACCEPT4_RET_TYPE, LIBC_ACCEPT4_SIG) 93 | 94 | /* 95 | * Torsocks call for accept4(2). 96 | */ 97 | LIBC_ACCEPT4_RET_TYPE tsocks_accept4(LIBC_ACCEPT4_SIG) 98 | { 99 | int ret; 100 | socklen_t sa_len; 101 | struct sockaddr sa; 102 | 103 | if (tsocks_config.allow_inbound) { 104 | /* Allowed by the user so directly go to the libc. */ 105 | goto libc_call; 106 | } 107 | 108 | sa_len = sizeof(sa); 109 | 110 | ret = getsockname(sockfd, &sa, &sa_len); 111 | if (ret < 0) { 112 | PERROR("[accept4] getsockname"); 113 | goto error; 114 | } 115 | 116 | /* 117 | * accept4() on a Unix socket is allowed else we are going to try to match 118 | * it on INET localhost socket. 119 | */ 120 | if (sa.sa_family == AF_UNIX) { 121 | goto libc_call; 122 | } 123 | 124 | /* Inbound localhost connections are allowed. */ 125 | ret = utils_sockaddr_is_localhost(&sa); 126 | if (!ret) { 127 | 128 | /* 129 | * Accept is completely denied here since this means that the 130 | * application can accept inbound connections on non localhost that are 131 | * obviously NOT handled by the Tor network thus reject this call. 132 | */ 133 | DBG("[accept4] Non localhost inbound connection are not allowed."); 134 | errno = EPERM; 135 | goto error; 136 | } 137 | 138 | libc_call: 139 | return tsocks_libc_accept4(LIBC_ACCEPT4_ARGS); 140 | 141 | error: 142 | return -1; 143 | } 144 | 145 | /* 146 | * Libc hijacked symbol accept4(2). 147 | */ 148 | LIBC_ACCEPT4_DECL 149 | { 150 | if (!tsocks_libc_accept4) { 151 | tsocks_initialize(); 152 | tsocks_libc_accept4 = tsocks_find_libc_symbol( 153 | LIBC_ACCEPT4_NAME_STR, TSOCKS_SYM_EXIT_NOT_FOUND); 154 | } 155 | 156 | return tsocks_accept4(LIBC_ACCEPT4_ARGS); 157 | } 158 | #endif 159 | -------------------------------------------------------------------------------- /src/lib/close.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with 14 | * this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #include 19 | #include 20 | 21 | #include "torsocks.h" 22 | 23 | /* close(2) */ 24 | TSOCKS_LIBC_DECL(close, LIBC_CLOSE_RET_TYPE, LIBC_CLOSE_SIG) 25 | 26 | /* 27 | * Torsocks call for close(2). 28 | */ 29 | LIBC_CLOSE_RET_TYPE tsocks_close(LIBC_CLOSE_SIG) 30 | { 31 | struct connection *conn; 32 | 33 | DBG("[close] Close caught for fd %d", fd); 34 | 35 | connection_registry_lock(); 36 | conn = connection_find(fd); 37 | if (conn) { 38 | /* 39 | * Remove from the registry so it's not visible anymore and thus using 40 | * it without lock. 41 | */ 42 | connection_remove(conn); 43 | } 44 | connection_registry_unlock(); 45 | 46 | /* 47 | * Put back the connection reference. If the refcount get to 0, the 48 | * connection pointer is destroyed. 49 | */ 50 | if (conn) { 51 | DBG("[close] Close connection putting back ref"); 52 | connection_put_ref(conn); 53 | } 54 | 55 | /* 56 | * Let the log system detect when the log file fd is about to be 57 | * closed and clean up. 58 | */ 59 | log_fd_close_notify(fd); 60 | 61 | /* Return the original libc close. */ 62 | return tsocks_libc_close(fd); 63 | } 64 | 65 | /* 66 | * Libc hijacked symbol close(2). 67 | */ 68 | LIBC_CLOSE_DECL 69 | { 70 | if (!tsocks_libc_close) { 71 | tsocks_initialize(); 72 | } 73 | return tsocks_close(LIBC_CLOSE_ARGS); 74 | } 75 | -------------------------------------------------------------------------------- /src/lib/connect.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2000-2008 - Shaun Clowes 3 | * 2008-2011 - Robert Hogan 4 | * 2013 - David Goulet 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License, version 2 only, as 8 | * published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 | * more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along with 16 | * this program; if not, write to the Free Software Foundation, Inc., 51 17 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "torsocks.h" 28 | 29 | /* connect(2) */ 30 | TSOCKS_LIBC_DECL(connect, LIBC_CONNECT_RET_TYPE, LIBC_CONNECT_SIG) 31 | 32 | /* 33 | * Validate the given sock fd and address that we receive in the connect() 34 | * call. Criteria are: 35 | * 36 | * -) Non INET/INET6 socket should return to the libc, LIBC. 37 | * -) Non stream socket can't be handled, DENY. 38 | * -) Connection to the any address won't work with Tor, DENY. 39 | * -) ALLOW. 40 | * 41 | * Return 0 if validation passes and socket handling should continue. Return 1 42 | * if the socket can't be handle by Tor but is still valid thus the caller 43 | * should send it directly to the libc connect function. 44 | * 45 | * On error or if validation fails, errno is set and -1 is returned. The caller 46 | * should *return* right away an error. 47 | */ 48 | int tsocks_validate_socket(int sockfd, const struct sockaddr *addr) 49 | { 50 | int ret, sock_type; 51 | socklen_t optlen; 52 | 53 | if (!addr) { 54 | /* Go directly to libc, connect() will handle a NULL value. */ 55 | goto libc_call; 56 | } 57 | 58 | /* 59 | * We can't handle a non inet socket thus directly go to the libc. This is 60 | * to allow AF_UNIX/_LOCAL socket to work with torsocks. 61 | */ 62 | if (addr->sa_family != AF_INET && addr->sa_family != AF_INET6) { 63 | DBG("[connect] Connection is not IPv4/v6. Ignoring."); 64 | /* Ask the call to use the libc connect. */ 65 | goto libc_call; 66 | } 67 | 68 | optlen = sizeof(sock_type); 69 | ret = getsockopt(sockfd, SOL_SOCKET, SO_TYPE, &sock_type, &optlen); 70 | if (ret < 0) { 71 | DBG("[connect] Fail getsockopt() on sock %d", sockfd); 72 | errno = EBADF; 73 | goto error; 74 | } 75 | 76 | DBG("[connect] Socket family %s and type %d", 77 | addr->sa_family == AF_INET ? "AF_INET" : "AF_INET6", sock_type); 78 | 79 | if (!IS_SOCK_STREAM(sock_type)) { 80 | if ((tsocks_config.allow_outbound_localhost == 2) && 81 | IS_SOCK_DGRAM(sock_type) && utils_sockaddr_is_localhost(addr)) { 82 | DBG("[connect] Allowing localhost UDP socket."); 83 | goto libc_call; 84 | } 85 | 86 | /* Refuse non stream socket since Tor can't handle that. */ 87 | DBG("[connect] UDP or ICMP stream can't be handled. Rejecting."); 88 | errno = EPERM; 89 | goto error; 90 | } 91 | 92 | /* 93 | * Trying to connect to ANY address will evidently not work for Tor thus we 94 | * deny the call with an invalid argument error. 95 | */ 96 | if (utils_is_addr_any(addr)) { 97 | errno = EPERM; 98 | goto error; 99 | } 100 | 101 | return 0; 102 | 103 | libc_call: 104 | return 1; 105 | error: 106 | return -1; 107 | } 108 | 109 | /* 110 | * Torsocks call for connect(2). 111 | */ 112 | LIBC_CONNECT_RET_TYPE tsocks_connect(LIBC_CONNECT_SIG) 113 | { 114 | int ret, ret_errno; 115 | struct connection *new_conn; 116 | struct onion_entry *on_entry; 117 | 118 | DBG("Connect caught on fd %d", sockfd); 119 | 120 | /* 121 | * Validate socket values in order to see if we can handle this connect 122 | * through Tor. 123 | */ 124 | ret = tsocks_validate_socket(sockfd, addr); 125 | if (ret == 1) { 126 | /* Tor can't handle it so send it to the libc. */ 127 | goto libc_connect; 128 | } else if (ret == -1) { 129 | /* Validation failed. Stop right now. */ 130 | goto error; 131 | } 132 | /* Implicit else statement meaning we continue processing the connect. */ 133 | assert(!ret); 134 | 135 | /* 136 | * Lock registry to get the connection reference if one. In this code path, 137 | * if a connection object is found, it will not be used since a double 138 | * connect() on the same file descriptor is an error so the registry is 139 | * quickly unlocked and no reference is needed. 140 | */ 141 | connection_registry_lock(); 142 | new_conn = connection_find(sockfd); 143 | connection_registry_unlock(); 144 | if (new_conn) { 145 | /* Double connect() for the same fd. */ 146 | errno = EISCONN; 147 | goto error; 148 | } 149 | 150 | /* 151 | * See if the IP being connected is an onion IP cookie mapping to an 152 | * existing .onion address. 153 | */ 154 | onion_pool_lock(&tsocks_onion_pool); 155 | on_entry = onion_entry_find_by_addr(addr, &tsocks_onion_pool); 156 | onion_pool_unlock(&tsocks_onion_pool); 157 | if (on_entry) { 158 | /* 159 | * Create a connection with the onion IP cookie since getpeername() 160 | * might need it, and set connection domain and hostname to use 161 | * the onion address name found before. 162 | */ 163 | new_conn = connection_create(sockfd, addr); 164 | if (!new_conn) { 165 | errno = ENOMEM; 166 | goto error; 167 | } 168 | new_conn->dest_addr.domain = CONNECTION_DOMAIN_NAME; 169 | new_conn->dest_addr.hostname.port = utils_get_port_from_addr(addr); 170 | new_conn->dest_addr.hostname.addr = strdup(on_entry->hostname); 171 | if (!new_conn->dest_addr.hostname.addr) { 172 | ret_errno = ENOMEM; 173 | goto error_free; 174 | } 175 | } else { 176 | /* 177 | * Check if address is localhost. At this point, we are sure it's not a 178 | * .onion cookie address that is by default in the loopback network 179 | * thus this check is done after the onion entry lookup. 180 | */ 181 | if (utils_sockaddr_is_localhost(addr)) { 182 | /* 183 | * Certain setups need to be able to reach localhost, despite 184 | * running torsocks. If they enabled the config option, allow such 185 | * connections. 186 | */ 187 | if (tsocks_config.allow_outbound_localhost) { 188 | goto libc_connect; 189 | } 190 | 191 | WARN("[connect] Connection to a local address are denied since it " 192 | "might be a TCP DNS query to a local DNS server. " 193 | "Rejecting it for safety reasons."); 194 | errno = EPERM; 195 | goto error; 196 | } 197 | 198 | new_conn = connection_create(sockfd, addr); 199 | if (!new_conn) { 200 | errno = ENOMEM; 201 | goto error; 202 | } 203 | } 204 | 205 | /* Connect the socket to the Tor network. */ 206 | ret = tsocks_connect_to_tor(new_conn); 207 | if (ret < 0) { 208 | ret_errno = -ret; 209 | goto error_free; 210 | } 211 | 212 | connection_registry_lock(); 213 | /* This can't fail since a lookup was done previously. */ 214 | connection_insert(new_conn); 215 | connection_registry_unlock(); 216 | 217 | /* Flag errno for success */ 218 | ret = errno = 0; 219 | return ret; 220 | 221 | libc_connect: 222 | return tsocks_libc_connect(LIBC_CONNECT_ARGS); 223 | 224 | error_free: 225 | /* 226 | * Put back reference of newly created connection. Will be freed if 227 | * refcount goes down to 0. 228 | */ 229 | connection_put_ref(new_conn); 230 | errno = ret_errno; 231 | error: 232 | /* At this point, errno MUST be set to a valid connect() error value. */ 233 | return -1; 234 | } 235 | 236 | /* 237 | * Libc hijacked symbol connect(2). 238 | */ 239 | LIBC_CONNECT_DECL 240 | { 241 | if (!tsocks_libc_connect) 242 | tsocks_initialize(); 243 | return tsocks_connect(LIBC_CONNECT_ARGS); 244 | } 245 | -------------------------------------------------------------------------------- /src/lib/execve.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along 14 | * with this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #include 19 | #include 20 | 21 | #include "torsocks.h" 22 | 23 | /* execve(2) */ 24 | TSOCKS_LIBC_DECL(execve, LIBC_EXECVE_RET_TYPE, LIBC_EXECVE_SIG) 25 | 26 | /* 27 | * Check the file for setuid or security capabilities. Return 1 if 28 | * capabilities or suid is set which indicates that LD_PRELOAD will be 29 | * stripped. If none of those are present, return 0. 30 | */ 31 | int 32 | check_cap_suid(const char *filename) 33 | { 34 | struct stat perms; 35 | 36 | if (stat(filename, &perms) == 0) { 37 | if (perms.st_mode & (S_ISUID | S_ISGID)) { 38 | /* setXuid is enabled, LD_PRELOAD will be stripped */ 39 | return -1; 40 | } 41 | } 42 | 43 | /* Capabilities as such are just on Linux. */ 44 | #ifdef __linux__ 45 | #include 46 | static const char *sec_cap = "security.capability"; 47 | ssize_t len = getxattr(filename, sec_cap, NULL, 0); 48 | if (len > 0) { 49 | /* security capabilities are set, LD_PRELOAD will be stripped */ 50 | return -1; 51 | } 52 | /* On failure or a value of zero, either no caps are present or the 53 | * filename wasn't found so in both cases, let execve() call handle the 54 | * failure if one. */ 55 | #endif /* __linux__ */ 56 | 57 | return 0; 58 | } 59 | 60 | /* 61 | * execve() is hijacked to avoid executing setuid or setcap binaries which 62 | * will strip the LD_PRELOAD settings. 63 | */ 64 | LIBC_EXECVE_RET_TYPE tsocks_execve(LIBC_EXECVE_SIG) 65 | { 66 | if (check_cap_suid(filename) < 0) { 67 | errno = EPERM; 68 | return -1; 69 | } 70 | return tsocks_libc_execve(filename, argv, envp); 71 | } 72 | 73 | /* 74 | * Libc hijacked symbol execve(2). 75 | */ 76 | LIBC_EXECVE_DECL 77 | { 78 | if (!tsocks_libc_execve) { 79 | tsocks_initialize(); 80 | } 81 | return tsocks_execve(LIBC_EXECVE_ARGS); 82 | } 83 | -------------------------------------------------------------------------------- /src/lib/exit.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) - 2013 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with 14 | * this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include "torsocks.h" 23 | 24 | /* 25 | * _exit() and _Exit are hijacked here so we can cleanup torsocks library 26 | * safely since the destructor is *not* called for these functions. 27 | */ 28 | 29 | void _exit(int status) 30 | { 31 | static void (*plibc_func)(int) = NULL; 32 | 33 | if (plibc_func == NULL) { 34 | plibc_func = dlsym(RTLD_NEXT, "_exit"); 35 | if (plibc_func == NULL) { 36 | ERR("unable to find \"_exit\" symbol"); 37 | errno = ENOSYS; 38 | } 39 | } 40 | 41 | tsocks_cleanup(); 42 | 43 | if (plibc_func) { 44 | plibc_func(status); 45 | } 46 | 47 | /* 48 | * This should never be reached but for the sake of the compiler 49 | * not complaining, this function MUST never return. 50 | */ 51 | abort(); 52 | } 53 | 54 | void _Exit(int status) 55 | { 56 | static void (*plibc_func)(int) = NULL; 57 | 58 | if (plibc_func == NULL) { 59 | plibc_func = dlsym(RTLD_NEXT, "_Exit"); 60 | if (plibc_func == NULL) { 61 | ERR("unable to find \"_Exit\" symbol"); 62 | errno = ENOSYS; 63 | } 64 | } 65 | 66 | tsocks_cleanup(); 67 | 68 | if (plibc_func) { 69 | plibc_func(status); 70 | } 71 | 72 | /* 73 | * This should never be reached but for the sake of the compiler 74 | * not complaining, this function MUST never return. 75 | */ 76 | abort(); 77 | } 78 | -------------------------------------------------------------------------------- /src/lib/fclose.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with 14 | * this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #include 19 | #include 20 | 21 | #include "torsocks.h" 22 | 23 | /* fclose(3) */ 24 | TSOCKS_LIBC_DECL(fclose, LIBC_FCLOSE_RET_TYPE, LIBC_FCLOSE_SIG) 25 | 26 | /* 27 | * Torsocks call for fclose(3). 28 | */ 29 | LIBC_FCLOSE_RET_TYPE tsocks_fclose(LIBC_FCLOSE_SIG) 30 | { 31 | int fd; 32 | struct connection *conn; 33 | 34 | if (!fp) { 35 | errno = EBADF; 36 | goto error; 37 | } 38 | 39 | fd = fileno(fp); 40 | if (fd < 0) { 41 | /* errno is set to EBADF here by fileno(). */ 42 | goto error; 43 | } 44 | 45 | DBG("[fclose] Close caught for fd %d", fd); 46 | 47 | connection_registry_lock(); 48 | conn = connection_find(fd); 49 | if (conn) { 50 | /* 51 | * Remove from the registry so it's not visible anymore and thus using 52 | * it without lock. 53 | */ 54 | connection_remove(conn); 55 | } 56 | connection_registry_unlock(); 57 | 58 | /* 59 | * Put back the connection reference. If the refcount get to 0, the 60 | * connection pointer is destroyed. 61 | */ 62 | if (conn) { 63 | DBG("Close connection putting back ref"); 64 | connection_put_ref(conn); 65 | } 66 | 67 | /* Return the original libc fclose. */ 68 | return tsocks_libc_fclose(fp); 69 | 70 | error: 71 | return -1; 72 | } 73 | 74 | /* 75 | * Libc hijacked symbol fclose(3). 76 | */ 77 | LIBC_FCLOSE_DECL 78 | { 79 | /* fclose(3) is unique in that it does not call torsocks_initialize(), as 80 | * it is used from within the initialization routine to close the config 81 | * file/log file. This would be a problem, except that all of the global 82 | * state it depends on is statically initialized. */ 83 | if (!tsocks_libc_fclose) { 84 | tsocks_libc_fclose = tsocks_find_libc_symbol( 85 | LIBC_FCLOSE_NAME_STR, TSOCKS_SYM_EXIT_NOT_FOUND); 86 | } 87 | return tsocks_fclose(LIBC_FCLOSE_ARGS); 88 | } 89 | -------------------------------------------------------------------------------- /src/lib/getaddrinfo.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2000-2008 - Shaun Clowes 3 | * 2008-2011 - Robert Hogan 4 | * 2013 - David Goulet 5 | * 6 | * This program is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU General Public License, version 2 only, as 8 | * published by the Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 | * more details. 14 | * 15 | * You should have received a copy of the GNU General Public License along with 16 | * this program; if not, write to the Free Software Foundation, Inc., 51 17 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | #include "torsocks.h" 26 | 27 | /* getaddrinfo(3) */ 28 | TSOCKS_LIBC_DECL(getaddrinfo, LIBC_GETADDRINFO_RET_TYPE, 29 | LIBC_GETADDRINFO_SIG) 30 | 31 | /* 32 | * Torsocks call for getaddrinfo(3). 33 | */ 34 | LIBC_GETADDRINFO_RET_TYPE tsocks_getaddrinfo(LIBC_GETADDRINFO_SIG) 35 | { 36 | int ret, af; 37 | struct in_addr addr4; 38 | struct in6_addr addr6; 39 | void *addr; 40 | char *ip_str, ipv4[INET_ADDRSTRLEN], ipv6[INET6_ADDRSTRLEN]; 41 | socklen_t ip_str_size; 42 | const char *tmp_node; 43 | 44 | DBG("[getaddrinfo] Requesting %s hostname", node); 45 | 46 | if (!node) { 47 | /* 48 | * As stated in the man page, if node is NULL, the libc call will 49 | * return a valid socket address but NO external DNS resolution is 50 | * possible since there is no host name to resolve. 51 | */ 52 | tmp_node = node; 53 | goto libc_call; 54 | } 55 | 56 | /* 57 | * Quoting the getaddrinfo(3) man page: 58 | * 59 | * All the other fields in the structure pointed to by hints must 60 | * contain either 0 or a NULL pointer, as appropriate. Specifying hints 61 | * as NULL is equivalent to setting ai_socktype and ai_protocol to 62 | * 0; ai_family to AF_UNSPEC; and ai_flags to (AI_V4MAPPED | 63 | * AI_ADDRCONFIG). 64 | * 65 | * This means that for sure the ai_family will be treated as AF_UNSPEC. 66 | */ 67 | if (!hints) { 68 | tmp_node = node; 69 | goto libc_call; 70 | } 71 | 72 | /* Use right domain for the next step. */ 73 | switch (hints->ai_family) { 74 | default: 75 | /* Default value is to use IPv4. */ 76 | case AF_INET: 77 | addr = &addr4; 78 | ip_str = ipv4; 79 | ip_str_size = sizeof(ipv4); 80 | af = AF_INET; 81 | break; 82 | case AF_INET6: 83 | addr = &addr6; 84 | ip_str = ipv6; 85 | ip_str_size = sizeof(ipv6); 86 | af = AF_INET6; 87 | break; 88 | } 89 | 90 | ret = inet_pton(af, node, addr); 91 | if (ret == 0) { 92 | /* If AI_NUMERICHOST is set, return a error. */ 93 | if (hints->ai_flags & AI_NUMERICHOST) { 94 | ret = EAI_NONAME; 95 | goto error; 96 | } 97 | 98 | /* The node most probably is a DNS name. */ 99 | ret = tsocks_tor_resolve(af, node, addr); 100 | if (ret < 0) { 101 | ret = EAI_FAIL; 102 | goto error; 103 | } 104 | 105 | (void) inet_ntop(af, addr, ip_str, ip_str_size); 106 | tmp_node = ip_str; 107 | DBG("[getaddrinfo] Node %s resolved to %s", node,tmp_node); 108 | } else { 109 | tmp_node = node; 110 | DBG("[getaddrinfo] Node %s will be passed to the libc call", tmp_node); 111 | } 112 | 113 | libc_call: 114 | ret = tsocks_libc_getaddrinfo(tmp_node, service, hints, res); 115 | if (ret) { 116 | goto error; 117 | } 118 | 119 | return 0; 120 | 121 | error: 122 | return ret; 123 | } 124 | 125 | /* 126 | * Libc hijacked symbol getaddrinfo(3). 127 | */ 128 | LIBC_GETADDRINFO_DECL 129 | { 130 | if (!tsocks_libc_getaddrinfo) { 131 | tsocks_initialize(); 132 | tsocks_libc_getaddrinfo = tsocks_find_libc_symbol( 133 | LIBC_GETADDRINFO_NAME_STR, TSOCKS_SYM_EXIT_NOT_FOUND); 134 | } 135 | 136 | return tsocks_getaddrinfo(LIBC_GETADDRINFO_ARGS); 137 | } 138 | -------------------------------------------------------------------------------- /src/lib/getpeername.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with 14 | * this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | #include "torsocks.h" 24 | 25 | /* getpeername(2) */ 26 | TSOCKS_LIBC_DECL(getpeername, LIBC_GETPEERNAME_RET_TYPE, 27 | LIBC_GETPEERNAME_SIG) 28 | 29 | /* 30 | * Torsocks call for getpeername(2). 31 | */ 32 | LIBC_GETPEERNAME_RET_TYPE tsocks_getpeername(LIBC_GETPEERNAME_SIG) 33 | { 34 | int ret = 0; 35 | struct connection *conn; 36 | socklen_t sz = 0; 37 | 38 | DBG("[getpeername] Requesting address on socket %d", sockfd); 39 | 40 | connection_registry_lock(); 41 | conn = connection_find(sockfd); 42 | if (!conn) { 43 | connection_registry_unlock(); 44 | goto libc; 45 | } 46 | 47 | if (!addrlen || !addr) { 48 | /* Bad address. */ 49 | errno = EFAULT; 50 | ret = -1; 51 | goto end; 52 | } 53 | 54 | /* 55 | * Copy the minimum of *addrlen and the size of the actual address 56 | * into the given addr. There are applications that pass in buffers 57 | * that are rather large, which is acceptable behavior. 58 | */ 59 | switch (conn->dest_addr.domain) { 60 | case CONNECTION_DOMAIN_NAME: 61 | /* 62 | * This domain is only used with onion address which contains a 63 | * cookie address of domain INET. Use that since that's the address 64 | * that has been returned to the application. 65 | */ 66 | case CONNECTION_DOMAIN_INET: 67 | sz = min(sizeof(conn->dest_addr.u.sin), *addrlen); 68 | memcpy(addr, (const struct sockaddr *) &conn->dest_addr.u.sin, 69 | sz); 70 | break; 71 | case CONNECTION_DOMAIN_INET6: 72 | sz = min(sizeof(conn->dest_addr.u.sin6), *addrlen); 73 | memcpy(addr, (const struct sockaddr *) &conn->dest_addr.u.sin6, 74 | sz); 75 | break; 76 | } 77 | 78 | /* Success. */ 79 | *addrlen = sz; 80 | errno = 0; 81 | ret = 0; 82 | 83 | end: 84 | connection_registry_unlock(); 85 | return ret; 86 | 87 | libc: 88 | /* 89 | * This is clearly not a socket we are handling so it's safe to pass it to 90 | * the original libc call. 91 | */ 92 | return tsocks_libc_getpeername(LIBC_GETPEERNAME_ARGS); 93 | } 94 | 95 | /* 96 | * Libc hijacked symbol getpeername(2). 97 | */ 98 | LIBC_GETPEERNAME_DECL 99 | { 100 | if (!tsocks_libc_getpeername) { 101 | tsocks_initialize(); 102 | tsocks_libc_getpeername = tsocks_find_libc_symbol( 103 | LIBC_GETPEERNAME_NAME_STR, TSOCKS_SYM_EXIT_NOT_FOUND); 104 | } 105 | 106 | return tsocks_getpeername(LIBC_GETPEERNAME_ARGS); 107 | } 108 | -------------------------------------------------------------------------------- /src/lib/listen.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with 14 | * this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #include 19 | 20 | #include 21 | 22 | #include "torsocks.h" 23 | 24 | TSOCKS_LIBC_DECL(listen, LIBC_LISTEN_RET_TYPE, LIBC_LISTEN_SIG) 25 | 26 | /* 27 | * Torsocks call for listen(2). 28 | */ 29 | LIBC_LISTEN_RET_TYPE tsocks_listen(LIBC_LISTEN_SIG) 30 | { 31 | int ret; 32 | socklen_t addrlen; 33 | struct sockaddr sa; 34 | 35 | if (tsocks_config.allow_inbound) { 36 | /* Allowed by the user so directly go to the libc. */ 37 | goto libc_call; 38 | } 39 | 40 | addrlen = sizeof(sa); 41 | 42 | ret = getsockname(sockfd, &sa, &addrlen); 43 | if (ret < 0) { 44 | PERROR("[listen] getsockname"); 45 | goto error; 46 | } 47 | 48 | /* 49 | * Listen () on a Unix socket is allowed else we are going to try to match 50 | * it on INET localhost socket. 51 | */ 52 | if (sa.sa_family == AF_UNIX) { 53 | goto libc_call; 54 | } 55 | 56 | /* Inbound localhost connections are allowed. */ 57 | ret = utils_sockaddr_is_localhost(&sa); 58 | if (!ret) { 59 | /* 60 | * Listen is completely denied here since this means that the 61 | * application can accept inbound connections on non localhost that are 62 | * obviously NOT handled by the Tor network thus reject this call. 63 | */ 64 | DBG("[listen] Non localhost inbound connection are not allowed."); 65 | errno = EPERM; 66 | goto error; 67 | } 68 | 69 | libc_call: 70 | DBG("[listen] Passing listen fd %d to libc", sockfd); 71 | return tsocks_libc_listen(LIBC_LISTEN_ARGS); 72 | 73 | error: 74 | return -1; 75 | } 76 | 77 | /* 78 | * Libc hijacked symbol listen(2). 79 | */ 80 | LIBC_LISTEN_DECL 81 | { 82 | if (!tsocks_libc_listen) { 83 | tsocks_initialize(); 84 | tsocks_libc_listen = tsocks_find_libc_symbol( 85 | LIBC_LISTEN_NAME_STR, TSOCKS_SYM_EXIT_NOT_FOUND); 86 | } 87 | 88 | return tsocks_listen(LIBC_LISTEN_ARGS); 89 | } 90 | -------------------------------------------------------------------------------- /src/lib/recv.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with 14 | * this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | #include "torsocks.h" 24 | 25 | /* recvmsg(2) */ 26 | TSOCKS_LIBC_DECL(recvmsg, LIBC_RECVMSG_RET_TYPE, LIBC_RECVMSG_SIG) 27 | 28 | /* 29 | * This is the maximum hardcoded amount of fd that is possible to pass through 30 | * a Unix socket in the Linux kernel. On FreeBSD for instance it's MLEN which 31 | * is defined to MSIZE (256) minus the msg header size thus way below this 32 | * Linux limit. Such a shame there is no way to dynamically get that value or 33 | * get it in an exposed ABI... 34 | */ 35 | #define SCM_MAX_FD 253 36 | 37 | /* 38 | * Close all fds in the given array of size count. 39 | */ 40 | static void close_fds(int *fds, size_t count) 41 | { 42 | size_t i; 43 | 44 | for (i = 0; i < count; i++) { 45 | tsocks_libc_close(fds[i]); 46 | } 47 | } 48 | 49 | /* 50 | * Torsocks call for recvmsg(2) 51 | * 52 | * We only hijack this call to handle the FD passing between process on Unix 53 | * socket. If an INET/INET6 socket is recevied, we stop everything because at 54 | * that point we can't guarantee traffic going through Tor. 55 | * 56 | * Note that we don't rely on the given "msg" structure since it's controlled 57 | * by the user and might not have been zeroed thus containing wrong values for 58 | * ancillary data. Thus, we are going to expect SCM_MAX_FD and see what we can 59 | * get from that if any. 60 | */ 61 | LIBC_RECVMSG_RET_TYPE tsocks_recvmsg(LIBC_RECVMSG_SIG) 62 | { 63 | socklen_t addrlen; 64 | ssize_t ret = 0; 65 | char dummy, recv_fd[CMSG_SPACE(SCM_MAX_FD)]; 66 | struct iovec iov[1]; 67 | struct cmsghdr *cmsg; 68 | struct msghdr msg_hdr; 69 | struct sockaddr addr; 70 | 71 | /* Don't bother if the socket family is NOT Unix. */ 72 | addrlen = sizeof(addr); 73 | ret = getsockname(sockfd, &addr, &addrlen); 74 | if (ret < 0) { 75 | DBG("[recvmsg] Fail getsockname() on sock %d", sockfd); 76 | errno = EBADF; 77 | goto error; 78 | } 79 | if (addr.sa_family != AF_UNIX) { 80 | goto libc; 81 | } 82 | 83 | memset(&msg_hdr, 0, sizeof(msg_hdr)); 84 | 85 | /* Prepare to receive the structures */ 86 | iov[0].iov_base = &dummy; 87 | iov[0].iov_len = 1; 88 | msg_hdr.msg_iov = iov; 89 | msg_hdr.msg_iovlen = 1; 90 | msg_hdr.msg_control = recv_fd; 91 | msg_hdr.msg_controllen = sizeof(recv_fd); 92 | 93 | do { 94 | /* Just peek the data to inspect the payload for fd. */ 95 | ret = tsocks_libc_recvmsg(sockfd, &msg_hdr, MSG_PEEK | flags); 96 | } while (ret < 0 && errno == EINTR); 97 | if (ret < 0) { 98 | /* Use the current errno set by the call above. */ 99 | goto error; 100 | } 101 | cmsg = CMSG_FIRSTHDR(&msg_hdr); 102 | if (!cmsg) { 103 | /* No control message header, safe to pass to libc. */ 104 | goto libc; 105 | } 106 | if (msg_hdr.msg_flags & MSG_CTRUNC) { 107 | /* 108 | * This means there are actually *more* data in the control thus 109 | * exceeding somehow our hard limit of SCM_MAX_FD. In that case, return 110 | * an error since we can't guarantee anything for socket passing 111 | */ 112 | errno = EMSGSIZE; 113 | goto error; 114 | } 115 | 116 | /* 117 | * Detecting FD passing, the next snippet of code will check if we get a 118 | * inet/inet6 socket. If so, we are going to close the received socket, 119 | * wipe clean the cmsg payload and return an unauthorized access code. 120 | */ 121 | if (cmsg->cmsg_type == SCM_RIGHTS || cmsg->cmsg_level == SOL_SOCKET) { 122 | /* 123 | * The kernel control that len value and there is a hard limit so no 124 | * chance here of having a crazy high value that could exhaust the 125 | * stack memory. 126 | */ 127 | size_t i, sizeof_fds = (cmsg->cmsg_len - sizeof(*cmsg)) / sizeof(int); 128 | int fds[sizeof_fds]; 129 | 130 | memcpy(&fds, CMSG_DATA(cmsg), sizeof(fds)); 131 | 132 | /* 133 | * For each received fds, we will inspect them to see if there is an 134 | * inet socket in there and if so, we have to stop, close everything to 135 | * avoid fd leak and return an error. 136 | */ 137 | for (i = 0; i < sizeof_fds; i++) { 138 | struct sockaddr addr; 139 | socklen_t addrlen = sizeof(addr); 140 | 141 | memset(&addr, 0, addrlen); 142 | 143 | /* Get socket protocol family. */ 144 | ret = getsockname(fds[i], &addr, &addrlen); 145 | if (ret < 0) { 146 | /* Either a bad fd or not a socket. */ 147 | continue; 148 | } 149 | 150 | if (addr.sa_family == AF_INET || addr.sa_family == AF_INET6) { 151 | DBG("[recvmsg] Inet socket passing detected. Denying it."); 152 | /* We found socket, close everything and return error. */ 153 | close_fds(fds, sizeof_fds); 154 | /* 155 | * The recv(2) man page does *not* mention that errno value 156 | * however it's acceptable because Linux LSM can return this 157 | * code if the access is denied in the application by a 158 | * security module. We are basically simulating this here. 159 | */ 160 | errno = EACCES; 161 | ret = -1; 162 | goto error; 163 | } 164 | } 165 | } 166 | 167 | /* At this point, NO socket was detected, continue to the libc safely. */ 168 | 169 | libc: 170 | return tsocks_libc_recvmsg(LIBC_RECVMSG_ARGS); 171 | 172 | error: 173 | return ret; 174 | } 175 | 176 | /* 177 | * Libc hijacked symbol recvmsg(2). 178 | */ 179 | LIBC_RECVMSG_DECL 180 | { 181 | if (!tsocks_libc_recvmsg) { 182 | tsocks_initialize(); 183 | tsocks_libc_recvmsg = tsocks_find_libc_symbol(LIBC_RECVMSG_NAME_STR, 184 | TSOCKS_SYM_EXIT_NOT_FOUND); 185 | } 186 | 187 | return tsocks_recvmsg(LIBC_RECVMSG_ARGS); 188 | } 189 | -------------------------------------------------------------------------------- /src/lib/sendto.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dgoulet/torsocks/d4b0a84bdf2a1895c8ec3091dc2767fd9f8c2d66/src/lib/sendto.c -------------------------------------------------------------------------------- /src/lib/socket.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with 14 | * this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #include 19 | 20 | #include 21 | 22 | #include "torsocks.h" 23 | 24 | /* socket(2) */ 25 | TSOCKS_LIBC_DECL(socket, LIBC_SOCKET_RET_TYPE, LIBC_SOCKET_SIG) 26 | 27 | /* 28 | * Torsocks call for socket(2) 29 | */ 30 | LIBC_SOCKET_RET_TYPE tsocks_socket(LIBC_SOCKET_SIG) 31 | { 32 | DBG("[socket] Creating socket with domain %d, type %d and protocol %d", 33 | domain, type, protocol); 34 | 35 | if (IS_SOCK_STREAM(type)) { 36 | /* 37 | * The socket family is not checked here since we accept local socket 38 | * (AF_UNIX) that can NOT do outbound traffic. 39 | */ 40 | goto end; 41 | } else { 42 | /* 43 | * Non INET[6] socket can't be handle by tor else create the socket. 44 | * The connect function will deny anything that Tor can NOT handle. 45 | */ 46 | if (domain != AF_INET && domain != AF_INET6) { 47 | goto end; 48 | } 49 | 50 | /* 51 | * If outbound localhost UDP traffic is allowed, then allow all UDP 52 | * socket creation. Validation on the destination addr is done at 53 | * connect()/sendto() time. 54 | */ 55 | if ((tsocks_config.allow_outbound_localhost == 2) && 56 | IS_SOCK_DGRAM(type)) { 57 | goto end; 58 | } 59 | 60 | /* 61 | * Print this message only in debug mode. Very often, applications uses 62 | * the libc to do DNS resolution which first tries with UDP and then 63 | * with TCP. It's not critical for the user to know that a non TCP 64 | * socket has been denied and since the libc has a fallback that works, 65 | * this message most of the time, simply polutes the application's 66 | * output which can cause issues with external applications parsing the 67 | * output. 68 | */ 69 | DBG("IPv4/v6 non TCP socket denied. Tor network can't handle it."); 70 | errno = EPERM; 71 | return -1; 72 | 73 | } 74 | 75 | end: 76 | /* Stream socket for INET/INET6 is good so open it. */ 77 | return tsocks_libc_socket(domain, type, protocol); 78 | } 79 | 80 | /* 81 | * Libc hijacked symbol socket(2). 82 | */ 83 | LIBC_SOCKET_DECL 84 | { 85 | if (!tsocks_libc_socket) 86 | tsocks_initialize(); 87 | return tsocks_socket(LIBC_SOCKET_ARGS); 88 | } 89 | -------------------------------------------------------------------------------- /src/lib/socketpair.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with 14 | * this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #include 19 | 20 | #include 21 | 22 | #include "torsocks.h" 23 | 24 | /* socketpair(2) */ 25 | TSOCKS_LIBC_DECL(socketpair, LIBC_SOCKETPAIR_RET_TYPE, LIBC_SOCKETPAIR_SIG) 26 | 27 | /* 28 | * Torsocks call for socketpair(2) 29 | */ 30 | LIBC_SOCKETPAIR_RET_TYPE tsocks_socketpair(LIBC_SOCKETPAIR_SIG) 31 | { 32 | DBG("[socketpair] Creating socket with domain %d, type %d and protocol %d", 33 | domain, type, protocol); 34 | 35 | if (domain == AF_INET || domain == AF_INET6) { 36 | DBG("Non TCP socketpair denied. Tor network can't handle it."); 37 | errno = EPERM; 38 | return -1; 39 | } 40 | 41 | /* Stream socket for INET/INET6 is good so open it. */ 42 | return tsocks_libc_socketpair(domain, type, protocol, sv); 43 | } 44 | 45 | /* 46 | * Libc hijacked symbol socketpair(2). 47 | */ 48 | LIBC_SOCKETPAIR_DECL 49 | { 50 | if (!tsocks_libc_socketpair) { 51 | tsocks_initialize(); 52 | tsocks_libc_socketpair = tsocks_find_libc_symbol( 53 | LIBC_SOCKETPAIR_NAME_STR, TSOCKS_SYM_EXIT_NOT_FOUND); 54 | } 55 | 56 | return tsocks_socketpair(LIBC_SOCKETPAIR_ARGS); 57 | } 58 | -------------------------------------------------------------------------------- /tests/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = utils unit 2 | 3 | TESTS = \ 4 | test_connect \ 5 | test_dns \ 6 | test_fd_passing \ 7 | test_getpeername \ 8 | test_socket \ 9 | # end of TESTS 10 | 11 | TAP_DRIVER = $(top_srcdir)/tests/tap-driver.sh 12 | TEST_LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) $(TAP_DRIVER) 13 | 14 | AM_CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src -I$(top_srcdir)/tests/utils/ -I$(srcdir) 15 | 16 | LIBTAP=$(top_builddir)/tests/utils/tap/libtap.la 17 | 18 | LIBTORSOCKS=$(top_builddir)/src/lib/libtorsocks.la 19 | 20 | HELPER_SOURCES = helpers.c helpers.h 21 | 22 | noinst_PROGRAMS = test_dns test_socket test_connect test_fd_passing test_getpeername 23 | 24 | test_dns_SOURCES = test_dns.c $(HELPER_SOURCES) 25 | test_dns_LDADD = $(LIBTAP) $(LIBTORSOCKS) 26 | 27 | test_socket_SOURCES = test_socket.c 28 | test_socket_LDADD = $(LIBTAP) $(LIBTORSOCKS) 29 | 30 | test_connect_SOURCES = test_connect.c 31 | test_connect_LDADD = $(LIBTAP) $(LIBTORSOCKS) 32 | 33 | test_fd_passing_SOURCES = test_fd_passing.c $(HELPER_SOURCES) 34 | test_fd_passing_LDADD = $(LIBTAP) $(LIBTORSOCKS) -lpthread 35 | 36 | test_getpeername_SOURCES = test_getpeername.c $(HELPER_SOURCES) 37 | test_getpeername_LDADD = $(LIBTAP) $(LIBTORSOCKS) 38 | -------------------------------------------------------------------------------- /tests/helpers.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along 14 | * with this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #include 19 | 20 | #include "lib/torsocks.h" 21 | 22 | #include "helpers.h" 23 | 24 | /* Try to connect to SocksPort localhost:9050 and if we can't skip. This is 25 | * to avoid to have failing test if no tor daemon is available. Return 1 if 26 | * true else 0. */ 27 | int 28 | helper_is_default_tor_running(void) 29 | { 30 | int ret, fd; 31 | struct sockaddr_in sa; 32 | 33 | fd = tsocks_libc_socket(AF_INET, SOCK_STREAM, 0); 34 | if (fd < 0) { 35 | goto end; 36 | } 37 | sa.sin_family = AF_INET; 38 | sa.sin_port = htons(9050); 39 | sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 40 | ret = tsocks_libc_connect(fd, (const struct sockaddr *) &sa, sizeof(sa)); 41 | close(fd); 42 | if (ret < 0) { 43 | goto end; 44 | } 45 | return 1; 46 | end: 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /tests/helpers.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2017 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along 14 | * with this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #ifndef TORSOCKS_HELPERS_H 19 | #define TORSOCKS_HELPERS_H 20 | 21 | int helper_is_default_tor_running(void); 22 | 23 | #endif /* TORSOCKS_HELPERS_H */ 24 | -------------------------------------------------------------------------------- /tests/test_connect.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with 14 | * this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | #include 26 | 27 | #define NUM_TESTS 8 28 | 29 | /* Suppress output messages. */ 30 | int tsocks_loglevel = MSGNONE; 31 | //int tsocks_loglevel = MSGDEBUG; 32 | 33 | static void test_connect_deny(void) 34 | { 35 | int fd, ret; 36 | struct sockaddr_in sin; 37 | struct sockaddr_in6 sin6; 38 | 39 | fd = tsocks_libc_socket(AF_INET, SOCK_RAW, IPPROTO_TCP); 40 | ret = connect(fd, (struct sockaddr *) &sin, sizeof(sin)); 41 | ok (ret == -1 && errno == EBADF, "Connect with RAW socket NOT valid"); 42 | close(fd); 43 | 44 | sin.sin_family = AF_INET; 45 | fd = tsocks_libc_socket(sin.sin_family, SOCK_DGRAM, 0); 46 | ret = connect(fd, (struct sockaddr *) &sin, sizeof(sin)); 47 | ok (ret == -1 && errno == EPERM, "Connect with UDP socket NOT valid"); 48 | close(fd); 49 | 50 | inet_pton(sin.sin_family, "0.0.0.0", &sin.sin_addr); 51 | fd = tsocks_libc_socket(sin.sin_family, SOCK_STREAM, 0); 52 | ret = connect(fd, (struct sockaddr *) &sin, sizeof(sin)); 53 | ok (ret == -1 && errno == EPERM, 54 | "Connect with ANY address is NOT valid."); 55 | close(fd); 56 | 57 | inet_pton(sin.sin_family, "127.0.0.1", &sin.sin_addr); 58 | fd = tsocks_libc_socket(sin.sin_family, SOCK_STREAM, 0); 59 | ret = connect(fd, (struct sockaddr *) &sin, sizeof(sin)); 60 | ok (ret == -1 && errno == EPERM, 61 | "Connect with local address is NOT valid."); 62 | close(fd); 63 | 64 | sin6.sin6_family = AF_INET6; 65 | fd = tsocks_libc_socket(sin6.sin6_family, SOCK_DGRAM, 0); 66 | ret = connect(fd, (struct sockaddr *) &sin6, sizeof(sin6)); 67 | ok (ret == -1 && errno == EPERM, "Connect with UDPv6 socket NOT valid"); 68 | close(fd); 69 | 70 | inet_pton(sin6.sin6_family, "::", &sin6.sin6_addr); 71 | fd = tsocks_libc_socket(sin6.sin6_family, SOCK_STREAM, 0); 72 | ret = connect(fd, (struct sockaddr *) &sin6, sizeof(sin6)); 73 | ok (ret == -1 && errno == EPERM, 74 | "Connect with ANYv6 address is NOT valid."); 75 | close(fd); 76 | 77 | inet_pton(sin6.sin6_family, "::1", &sin6.sin6_addr); 78 | fd = tsocks_libc_socket(sin6.sin6_family, SOCK_STREAM, 0); 79 | ret = connect(fd, (struct sockaddr *) &sin6, sizeof(sin6)); 80 | ok (ret == -1 && errno == EPERM, 81 | "Connect with local v6 address is NOT valid."); 82 | close(fd); 83 | 84 | /* Bad fd. */ 85 | ret = connect(42, (struct sockaddr *) &sin, 42); 86 | ok (ret == -1 && errno == EBADF, "Bad socket FD"); 87 | } 88 | 89 | int main(int argc, char **argv) 90 | { 91 | /* Libtap call for the number of tests planned. */ 92 | plan_tests(NUM_TESTS); 93 | 94 | test_connect_deny(); 95 | 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /tests/test_dns.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with 14 | * this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | #include 27 | #include "helpers.h" 28 | 29 | #define NUM_TESTS 6 30 | 31 | struct test_host { 32 | const char *name; 33 | const char *ip; 34 | }; 35 | 36 | /* Tor check hostname/ip. */ 37 | static const struct test_host tor_check = { 38 | .name = "perdulce.torproject.org", 39 | .ip = "138.201.14.203", 40 | }; 41 | 42 | /* moria1 directory authority. */ 43 | static const struct test_host tor_dir_auth1 = { 44 | .name = "belegost.csail.mit.edu", 45 | .ip = "128.31.0.39", 46 | }; 47 | 48 | /* maatuska directory authority. */ 49 | static const struct test_host tor_dir_auth2 = { 50 | .name = "maatuska.4711.se", 51 | .ip = "171.25.193.9", 52 | }; 53 | 54 | /* localhost resolution. */ 55 | static const struct test_host tor_localhost = { 56 | .name = "localhost", 57 | .ip = "127.0.0.1", 58 | }; 59 | 60 | static void test_gethostbyname(const struct test_host *host) 61 | { 62 | struct hostent *he; 63 | 64 | assert(host); 65 | 66 | diag("gethostbyname test"); 67 | 68 | he = gethostbyname(host->name); 69 | if (he) { 70 | char *addr = inet_ntoa(*((struct in_addr *) he->h_addr_list[0])); 71 | ok(strcmp(addr, host->ip) == 0, "Resolving %s", host->name); 72 | } else { 73 | fail("Resolving %s", host->name); 74 | } 75 | 76 | return; 77 | } 78 | 79 | static void test_gethostbyaddr_r_failed(void) 80 | { 81 | int result; 82 | in_addr_t addr; 83 | struct hostent ret; 84 | char buf[1024]; 85 | int buflen = sizeof buf; 86 | struct hostent *result_entp; 87 | int h_errno; 88 | 89 | diag("gethostbyaddr_r test"); 90 | 91 | /* RFC 6890 - An address from TEST-NET-1. Selected in hopes that it will 92 | + * _not_ reverse resolve to anything. 93 | + */ 94 | addr = inet_addr("192.0.2.1"); 95 | result = gethostbyaddr_r((const void *)&addr, 96 | INET_ADDRSTRLEN, AF_INET, &ret, buf, buflen, &result_entp, &h_errno); 97 | ok(0 != result, "Impossible reverse resolve failed as desired."); 98 | } 99 | 100 | static void test_gethostbyaddr_r(const struct test_host *host) 101 | { 102 | int result; 103 | in_addr_t addr; 104 | struct hostent ret; 105 | char buf[1024]; 106 | int buflen = sizeof buf; 107 | struct hostent *result_entp; 108 | int h_errno; 109 | 110 | assert(host); 111 | diag("gethostbyaddr_r test"); 112 | 113 | addr = inet_addr(host->ip); 114 | result = gethostbyaddr_r((const void *)&addr, 115 | INET_ADDRSTRLEN, AF_INET, &ret, buf, buflen, &result_entp, &h_errno); 116 | 117 | if (result) { 118 | fail("Resolving address %s: %d", host->ip, result); 119 | } 120 | 121 | if (strcmp(host->name, result_entp->h_name) != 0) { 122 | fail("Wrong resolved name: %s", result_entp->h_name); 123 | } 124 | 125 | if (result_entp->h_addrtype != AF_INET) { 126 | fail("Wrong resolved address family: %d", result_entp->h_addrtype); 127 | } 128 | 129 | ok(1, "Resolved address"); 130 | } 131 | 132 | static void test_gethostbyaddr(const struct test_host *host) 133 | { 134 | struct hostent *he; 135 | in_addr_t addr; 136 | 137 | assert(host); 138 | 139 | diag("gethostbyaddr test"); 140 | 141 | addr = inet_addr(host->ip); 142 | he = gethostbyaddr((const void *)&addr, INET_ADDRSTRLEN, AF_INET); 143 | if (he) { 144 | ok(strcmp(host->name, he->h_name) == 0, "Resolving address %s", host->ip); 145 | } else { 146 | fail("Resolving address %s", host->ip); 147 | } 148 | 149 | return; 150 | } 151 | 152 | static void test_getaddrinfo(const struct test_host *host) 153 | { 154 | int ret; 155 | struct addrinfo hints; 156 | struct addrinfo *result = NULL; 157 | 158 | diag("getaddrinfo test"); 159 | 160 | memset(&hints, 0, sizeof(struct addrinfo)); 161 | hints.ai_family = AF_INET; 162 | hints.ai_socktype = SOCK_STREAM; 163 | hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ 164 | hints.ai_protocol = 0; /* Any protocol */ 165 | hints.ai_canonname = NULL; 166 | hints.ai_addr = NULL; 167 | hints.ai_next = NULL; 168 | 169 | ret = getaddrinfo(host->name, NULL, &hints, &result); 170 | if (ret == 0) { 171 | struct in_addr addr; 172 | char *ip; 173 | 174 | addr.s_addr = ((struct sockaddr_in *)(result->ai_addr))->sin_addr.s_addr; 175 | ip = inet_ntoa(addr); 176 | 177 | ok(strcmp(host->ip, ip) == 0, 178 | "Resolving address %s with getaddrinfo", host->name); 179 | } else { 180 | printf("%s\n", gai_strerror(ret)); 181 | fail("Resolving address %s with getaddrinfo", host->name); 182 | } 183 | 184 | free(result); 185 | return; 186 | } 187 | 188 | int main(int argc, char **argv) 189 | { 190 | /* Try to connect to SocksPort localhost:9050 and if we can't skip. This is 191 | * to avoid to have failing test if no tor daemon is available. */ 192 | if (!helper_is_default_tor_running()) { 193 | goto end; 194 | } 195 | 196 | /* Libtap call for the number of tests planned. */ 197 | plan_tests(NUM_TESTS); 198 | 199 | test_getaddrinfo(&tor_check); 200 | test_gethostbyname(&tor_dir_auth1); 201 | test_gethostbyaddr(&tor_dir_auth2); 202 | test_gethostbyaddr_r(&tor_dir_auth2); 203 | test_gethostbyaddr_r_failed(); 204 | test_getaddrinfo(&tor_localhost); 205 | 206 | end: 207 | return 0; 208 | } 209 | -------------------------------------------------------------------------------- /tests/test_getpeername.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with 14 | * this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | #include 26 | #include "helpers.h" 27 | 28 | #define NUM_TESTS 7 29 | 30 | static void test_getpeername(void) 31 | { 32 | int pipe_fds[2], ret, inet_sock = -1; 33 | char buf[INET_ADDRSTRLEN]; 34 | struct sockaddr addr; 35 | struct sockaddr_in addrv4; 36 | struct sockaddr_storage ss; 37 | socklen_t addrlen; 38 | const char *ip = "128.31.0.39"; 39 | 40 | ret = pipe(pipe_fds); 41 | if (ret < 0) { 42 | fail("Unable to create pipe"); 43 | goto error; 44 | } 45 | 46 | /* This test is to see if we go through the libc or not. */ 47 | ret = getpeername(pipe_fds[0], NULL, NULL); 48 | ok(ret == -1 && errno == ENOTSOCK, "Invalid socket fd"); 49 | 50 | close(pipe_fds[0]); 51 | close(pipe_fds[1]); 52 | 53 | /* Create inet socket. */ 54 | inet_sock = socket(AF_INET, SOCK_STREAM, 0); 55 | ok(inet_sock >= 0, "Inet socket created"); 56 | 57 | /* This test is to see if we go through the libc or not. */ 58 | ret = getpeername(inet_sock, &addr, &addrlen); 59 | ok(ret == -1 && errno == ENOTCONN, "Socket not connected"); 60 | 61 | /* Connect socket through Tor so we can test the wrapper. */ 62 | addrv4.sin_family = AF_INET; 63 | addrv4.sin_port = htons(9131); 64 | inet_pton(addrv4.sin_family, ip, &addrv4.sin_addr); 65 | memset(addrv4.sin_zero, 0, sizeof(addrv4.sin_zero)); 66 | 67 | ret = connect(inet_sock, (struct sockaddr *) &addrv4, sizeof(addrv4)); 68 | if (ret < 0) { 69 | fail("Unable to connect to %s", ip); 70 | goto error; 71 | } 72 | 73 | /* Invalid arguments */ 74 | addrlen = sizeof(addr); 75 | ret = getpeername(inet_sock, NULL, &addrlen); 76 | ok(ret == -1 && errno == EFAULT, "Invalid addr ptr"); 77 | 78 | ret = getpeername(inet_sock, &addr, NULL); 79 | ok(ret == -1 && errno == EFAULT, "Invalid addrlen ptr"); 80 | 81 | addrlen = sizeof(addrv4); 82 | memset(&addrv4, 0, addrlen); 83 | ret = getpeername(inet_sock, (struct sockaddr *) &addrv4, &addrlen); 84 | 85 | /* Validate returned IP address. */ 86 | memset(buf, 0, sizeof(buf)); 87 | inet_ntop(addrv4.sin_family, &addrv4.sin_addr, buf, sizeof(buf)); 88 | ok(ret == 0 && strncmp(buf, ip, strlen(ip)) == 0, 89 | "Valid returned IP address from getpeername()"); 90 | 91 | /* Large but valid addrlen. */ 92 | addrlen = sizeof(ss); 93 | ret = getpeername(inet_sock, (struct sockaddr *)&ss, &addrlen); 94 | ok(ret == 0 && addrlen == sizeof(addrv4), 95 | "Valid returned IP address from getpeername(), large addrlen"); 96 | 97 | error: 98 | if (inet_sock >= 0) { 99 | close(inet_sock); 100 | } 101 | return; 102 | } 103 | 104 | int main(int argc, char **argv) 105 | { 106 | /* Try to connect to SocksPort localhost:9050 and if we can't skip. This is 107 | * to avoid to have failing test if no tor daemon is available. */ 108 | if (!helper_is_default_tor_running()) { 109 | goto end; 110 | } 111 | 112 | /* Libtap call for the number of tests planned. */ 113 | plan_tests(NUM_TESTS); 114 | 115 | test_getpeername(); 116 | 117 | end: 118 | return 0; 119 | } 120 | -------------------------------------------------------------------------------- /tests/test_socket.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with 14 | * this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | #include 26 | 27 | #define NUM_TESTS 18 28 | 29 | static void test_socketpair_types(void) 30 | { 31 | int fd[2], ret1, ret2, err; 32 | 33 | err = socketpair(AF_UNIX, SOCK_STREAM, 0, fd); 34 | ret1 = close(fd[0]); 35 | ret2 = close(fd[1]); 36 | ok (fd[0] != -1 && fd[1] != -1 && !err && ret1 == 0 && ret2 == 0, 37 | "Unix socket valid for socketpair"); 38 | 39 | err = socketpair(AF_INET, SOCK_STREAM, 0, fd); 40 | ok (err == -1 && errno == EPERM, "INET socket NOT valid for socketpair"); 41 | 42 | err = socketpair(AF_INET6, SOCK_STREAM, 0, fd); 43 | ok (err == -1 && errno == EPERM, "INET6 socket NOT valid for socketpair"); 44 | } 45 | 46 | static void test_socket_types(void) 47 | { 48 | int fd, ret; 49 | 50 | fd = socket(AF_UNIX, SOCK_STREAM, 0); 51 | ret = close(fd); 52 | ok (fd != -1 && ret == 0, "Unix socket is valid"); 53 | 54 | fd = socket(AF_LOCAL, SOCK_STREAM, 0); 55 | ret = close(fd); 56 | ok (fd != -1 && ret == 0, "AF local socket is valid"); 57 | 58 | fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); 59 | ret = close(fd); 60 | ok (fd != -1 && ret == 0, "IPv4 TCP socket is valid"); 61 | 62 | fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_IP); 63 | ret = close(fd); 64 | ok (fd != -1 && ret == 0, "IPv4 TCP non block socket is valid"); 65 | 66 | fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 67 | IPPROTO_IP); 68 | ret = close(fd); 69 | ok (fd != -1 && ret == 0, "IPv4 TCP non block/cloexec socket is valid"); 70 | 71 | fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP); 72 | ret = close(fd); 73 | ok (fd != -1 && ret == 0, "IPv6 TCP socket is valid"); 74 | 75 | fd = socket(AF_INET6, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_IP); 76 | ret = close(fd); 77 | ok (fd != -1 && ret == 0, "IPv6 TCP non block socket is valid"); 78 | 79 | fd = socket(AF_INET6, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 80 | IPPROTO_IP); 81 | ret = close(fd); 82 | ok (fd != -1 && ret == 0, "IPv6 TCP non block/cloexec socket is valid"); 83 | 84 | fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 85 | ok (fd == -1 && errno == EPERM, 86 | "IPv4 UDP socket is NOT valid"); 87 | 88 | fd = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP); 89 | ok (fd == -1 && errno == EPERM, 90 | "IPv4 UDP non block socket is NOT valid"); 91 | 92 | fd = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 93 | IPPROTO_UDP); 94 | ok (fd == -1 && errno == EPERM, 95 | "IPv4 UDP non block/cloexec socket is NOT valid"); 96 | 97 | fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 98 | ok (fd == -1 && errno == EPERM, 99 | "IPv6 UDP socket is NOT valid"); 100 | 101 | fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 102 | ok (fd == -1 && errno == EPERM, 103 | "IPv4 RAW socket is NOT valid"); 104 | 105 | fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 106 | ok (fd == -1 && errno == EPERM, 107 | "IPv4 RAW ICMP socket is NOT valid"); 108 | 109 | fd = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW); 110 | ok (fd == -1 && errno == EPERM, 111 | "IPv6 RAW socket is NOT valid"); 112 | } 113 | 114 | int main(int argc, char **argv) 115 | { 116 | /* Libtap call for the number of tests planned. */ 117 | plan_tests(NUM_TESTS); 118 | 119 | test_socket_types(); 120 | test_socketpair_types(); 121 | 122 | return 0; 123 | } 124 | -------------------------------------------------------------------------------- /tests/unit/Makefile.am: -------------------------------------------------------------------------------- 1 | TESTS = \ 2 | test_compat \ 3 | test_config-file \ 4 | test_connection \ 5 | test_onion \ 6 | test_socks5 \ 7 | test_utils \ 8 | # end of TESTS 9 | 10 | TAP_DRIVER = $(top_srcdir)/tests/tap-driver.sh 11 | TEST_LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) $(TAP_DRIVER) 12 | 13 | AM_CFLAGS = -I$(top_srcdir)/include \ 14 | -I$(top_srcdir)/src \ 15 | -I$(top_srcdir)/tests/utils/ \ 16 | -I$(srcdir) \ 17 | -I$(top_srcdir)/src/lib \ 18 | -DTORSOCKS_FIXTURE_PATH=\"`pwd`/fixtures/\" 19 | 20 | LIBTAP=$(top_builddir)/tests/utils/tap/libtap.la 21 | 22 | LIBCOMMON=$(top_builddir)/src/common/libcommon.la 23 | 24 | LIBTORSOCKS=$(top_builddir)/src/lib/libtorsocks.la 25 | 26 | noinst_PROGRAMS = test_onion test_connection test_utils test_config-file test_socks5 test_compat 27 | 28 | EXTRA_DIST = fixtures 29 | 30 | test_onion_SOURCES = test_onion.c 31 | test_onion_LDADD = $(LIBTAP) $(LIBCOMMON) 32 | 33 | test_connection_SOURCES = test_connection.c 34 | test_connection_LDADD = $(LIBTAP) $(LIBCOMMON) 35 | 36 | test_utils_SOURCES = test_utils.c 37 | test_utils_LDADD = $(LIBTAP) $(LIBCOMMON) 38 | 39 | test_config_file_SOURCES = test_config-file.c 40 | test_config_file_LDADD = $(LIBTAP) $(LIBCOMMON) 41 | 42 | test_socks5_SOURCES = test_socks5.c 43 | test_socks5_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBTORSOCKS) 44 | 45 | test_compat_SOURCES = test_compat.c 46 | test_compat_LDADD = $(LIBTAP) $(LIBCOMMON) $(LIBTORSOCKS) 47 | 48 | all-local: 49 | @if [ x"$(srcdir)" != x"$(builddir)" ]; then \ 50 | for script in $(EXTRA_DIST); do \ 51 | cp -rf $(srcdir)/$$script $(builddir); \ 52 | done; \ 53 | fi 54 | 55 | # Force remove here so make sure EXTRA_DIST does not contain something like 56 | # /usr. ;) 57 | clean-local: 58 | @if [ x"$(srcdir)" != x"$(builddir)" ]; then \ 59 | for script in $(EXTRA_DIST); do \ 60 | rm -rf $(builddir)/$$script; \ 61 | done; \ 62 | fi 63 | -------------------------------------------------------------------------------- /tests/unit/fixtures/config0: -------------------------------------------------------------------------------- 1 | # This is the configuration for libtorsocks (transparent socks) for use 2 | # with tor, which is providing a socks server on port 9050 by default. 3 | # 4 | # Lines beginning with # and blank lines are ignored 5 | # Much more documentation than provided in these comments can be found in 6 | # 7 | # torsocks.conf(5), torsocks(1) and torsocks(8) manpages. 8 | 9 | # Default Tor address and port. By default, Tor will listen on localhost for 10 | # any SOCKS connection and relay the traffic on the Tor network. 11 | TorAddress 127.0.0.1 12 | TorPort 9050 13 | 14 | # Tor hidden sites do not have real IP addresses. This specifies what range of 15 | # IP addresses will be handed to the application as "cookies" for .onion names. 16 | # Of course, you should pick a block of addresses which you aren't going to 17 | # ever need to actually connect to. This is similar to the MapAddress feature 18 | # of the main tor daemon. 19 | OnionAddrRange 127.42.42.0/24 20 | -------------------------------------------------------------------------------- /tests/unit/fixtures/config1: -------------------------------------------------------------------------------- 1 | # Empty config 2 | -------------------------------------------------------------------------------- /tests/unit/fixtures/config2: -------------------------------------------------------------------------------- 1 | TorPort 65536 2 | -------------------------------------------------------------------------------- /tests/unit/fixtures/config3: -------------------------------------------------------------------------------- 1 | TorPort 0 2 | -------------------------------------------------------------------------------- /tests/unit/fixtures/config4: -------------------------------------------------------------------------------- 1 | # invalid IPv4 2 | TorAddress 0.0 3 | -------------------------------------------------------------------------------- /tests/unit/fixtures/config5: -------------------------------------------------------------------------------- 1 | # invalid IPv6 2 | TorAddress 2001:::1 3 | -------------------------------------------------------------------------------- /tests/unit/fixtures/config6: -------------------------------------------------------------------------------- 1 | # invalid onion IPv4 range 2 | OnionAddrRange 127.42.42.0 3 | -------------------------------------------------------------------------------- /tests/unit/fixtures/config7: -------------------------------------------------------------------------------- 1 | # invalid onion IPv4 address 2 | OnionAddrRange 127.42.42.256/24 3 | -------------------------------------------------------------------------------- /tests/unit/fixtures/config8: -------------------------------------------------------------------------------- 1 | # invalid onion IPv6 address 2 | OnionAddrRange 2001:::1/64 3 | -------------------------------------------------------------------------------- /tests/unit/fixtures/config9_32: -------------------------------------------------------------------------------- 1 | # invalid onion mask 2 | OnionAddrRange 127.42.42.0/4294967295 3 | -------------------------------------------------------------------------------- /tests/unit/fixtures/config9_64: -------------------------------------------------------------------------------- 1 | # invalid onion mask 2 | OnionAddrRange 127.42.42.0/18446744073709551615 3 | -------------------------------------------------------------------------------- /tests/unit/test_compat.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with 14 | * this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | #include 26 | 27 | #define NUM_TESTS 7 28 | 29 | static void test_socket_stream(void) 30 | { 31 | int type, ret; 32 | 33 | type = SOCK_STREAM; 34 | ret = IS_SOCK_STREAM(type); 35 | ok (ret == 1, "Type SOCK_STREAM valid"); 36 | 37 | type = SOCK_STREAM | SOCK_NONBLOCK; 38 | ret = IS_SOCK_STREAM(type); 39 | ok (ret == 1, "Type SOCK_STREAM | SOCK_NONBLOCK valid"); 40 | 41 | type = SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC; 42 | ret = IS_SOCK_STREAM(type); 43 | ok (ret == 1, "Type SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC valid"); 44 | 45 | type = SOCK_STREAM | 42; 46 | ret = IS_SOCK_STREAM(type); 47 | ok (ret == 0, "Type SOCK_STREAM | 42 is NOT a stream socket"); 48 | 49 | type = SOCK_DGRAM; 50 | ret = IS_SOCK_STREAM(type); 51 | ok (ret == 0, "Type SOCK_DGRAM is NOT a stream socket"); 52 | 53 | type = SOCK_DGRAM | SOCK_NONBLOCK; 54 | ret = IS_SOCK_STREAM(type); 55 | ok (ret == 0, "Type SOCK_DGRAM | SOCK_NONBLOCK is NOT a stream socket"); 56 | 57 | type = SOCK_RAW; 58 | ret = IS_SOCK_STREAM(type); 59 | ok (ret == 0, "Type SOCK_RAW is NOT a stream socket"); 60 | } 61 | 62 | int main(int argc, char **argv) 63 | { 64 | /* Libtap call for the number of tests planned. */ 65 | plan_tests(NUM_TESTS); 66 | 67 | test_socket_stream(); 68 | 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /tests/unit/test_config-file.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 - David Goulet 3 | * Luke Gallagher 4 | * 5 | * This program is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License, version 2 only, as 7 | * published by the Free Software Foundation. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 | * more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along with 15 | * this program; if not, write to the Free Software Foundation, Inc., 51 16 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | #define NUM_TESTS 11 32 | 33 | static void test_config_file_read_none(void) 34 | { 35 | int ret = 0; 36 | struct configuration config; 37 | char buf[DEFAULT_DOMAIN_NAME_SIZE]; 38 | 39 | diag("Config file read none"); 40 | 41 | ret = config_file_read(NULL, &config); 42 | inet_ntop(AF_INET, &config.conf_file.onion_base, buf, sizeof(buf)); 43 | ok(ret == 0 && 44 | config.conf_file.tor_port == DEFAULT_TOR_PORT && 45 | strcmp(config.conf_file.tor_address, DEFAULT_TOR_ADDRESS) == 0 && 46 | strcmp(buf, DEFAULT_ONION_ADDR_RANGE) == 0 && 47 | config.conf_file.onion_mask == strtoul(DEFAULT_ONION_ADDR_MASK, NULL, 0), 48 | "Use default when no config file"); 49 | } 50 | 51 | static void test_config_file_read_valid(void) 52 | { 53 | int ret = 0; 54 | struct configuration config; 55 | char buf[DEFAULT_DOMAIN_NAME_SIZE]; 56 | 57 | diag("Config file read valid"); 58 | 59 | ret = config_file_read(fixture("config0"), &config); 60 | inet_ntop(AF_INET, &config.conf_file.onion_base, buf, sizeof(buf)); 61 | ok(ret == 0 && 62 | config.conf_file.tor_port == DEFAULT_TOR_PORT && 63 | strcmp(config.conf_file.tor_address, DEFAULT_TOR_ADDRESS) == 0 && 64 | strcmp(buf, DEFAULT_ONION_ADDR_RANGE) == 0 && 65 | config.conf_file.onion_mask == strtoul(DEFAULT_ONION_ADDR_MASK, NULL, 0), 66 | "Read valid config file"); 67 | } 68 | 69 | static void test_config_file_read_empty(void) 70 | { 71 | int ret = 0; 72 | struct configuration config; 73 | char buf[DEFAULT_DOMAIN_NAME_SIZE]; 74 | 75 | diag("Config file read empty"); 76 | 77 | ret = config_file_read(fixture("config1"), &config); 78 | inet_ntop(AF_INET, &config.conf_file.onion_base, buf, sizeof(buf)); 79 | ok(ret == 0 && 80 | config.conf_file.tor_port == 0 && 81 | config.conf_file.tor_address == NULL && 82 | strcmp(buf, "0.0.0.0") == 0 && 83 | config.conf_file.onion_mask == 0, 84 | "Read empty config file"); 85 | } 86 | 87 | static void test_config_file_read_invalid_values(void) 88 | { 89 | int ret = 0; 90 | struct configuration config; 91 | 92 | diag("Config file read invalid values"); 93 | 94 | ret = config_file_read(fixture("config2"), &config); 95 | ok(ret == -EINVAL && 96 | config.conf_file.tor_port == 0, 97 | "TorPort 65536 returns -EINVAL"); 98 | 99 | memset(&config, 0x0, sizeof(config)); 100 | ret = config_file_read(fixture("config3"), &config); 101 | ok(ret == -EINVAL && 102 | config.conf_file.tor_port == 0, 103 | "TorPort 0 returns -EINVAL"); 104 | 105 | memset(&config, 0x0, sizeof(config)); 106 | ret = config_file_read(fixture("config4"), &config); 107 | ok(ret == 0 && 108 | config.conf_file.tor_address == NULL, 109 | "TorAddress invalid IPv4 returns -1"); 110 | 111 | memset(&config, 0x0, sizeof(config)); 112 | ret = config_file_read(fixture("config5"), &config); 113 | ok(ret == 0 && 114 | config.conf_file.tor_address == NULL, 115 | "TorAddress invalid IPv6 returns -1"); 116 | 117 | memset(&config, 0x0, sizeof(config)); 118 | ret = config_file_read(fixture("config6"), &config); 119 | ok(ret == -EINVAL && 120 | config.conf_file.onion_mask == 0, 121 | "OnionAdrRange invalid range returns -EINVAL"); 122 | 123 | memset(&config, 0x0, sizeof(config)); 124 | ret = config_file_read(fixture("config7"), &config); 125 | ok(ret == -EINVAL && 126 | config.conf_file.onion_base == 0, 127 | "OnionAdrRange invalid IPv4 address returns -EINVAL"); 128 | 129 | memset(&config, 0x0, sizeof(config)); 130 | ret = config_file_read(fixture("config8"), &config); 131 | ok(ret == -EINVAL && 132 | config.conf_file.onion_base == 0, 133 | "OnionAdrRange invalid IPv6 address returns -EINVAL"); 134 | 135 | memset(&config, 0x0, sizeof(config)); 136 | #if (defined(__LP64__)) 137 | ret = config_file_read(fixture("config9_64"), &config); 138 | #else 139 | ret = config_file_read(fixture("config9_32"), &config); 140 | #endif 141 | ok(ret == -EINVAL && 142 | config.conf_file.onion_base == 0, 143 | "OnionAdrRange invalid mask returns -EINVAL"); 144 | } 145 | 146 | int main(int argc, char **argv) 147 | { 148 | /* Libtap call for the number of tests planned. */ 149 | plan_tests(NUM_TESTS); 150 | 151 | test_config_file_read_none(); 152 | skip_start(0 == TORSOCKS_FIXTURE_PATH, 10, "TORSOCKS_FIXTURE_PATH not defined"); 153 | test_config_file_read_valid(); 154 | test_config_file_read_empty(); 155 | test_config_file_read_invalid_values(); 156 | skip_end(); 157 | 158 | return exit_status(); 159 | } 160 | -------------------------------------------------------------------------------- /tests/unit/test_connection.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with 14 | * this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | #define NUM_TESTS 13 29 | 30 | static void test_connection_usage(void) 31 | { 32 | int ret; 33 | struct connection *conn, *conn2, *l_conn; 34 | struct connection_addr c_addr; 35 | 36 | diag("Connection subsystem creation test"); 37 | 38 | ret = connection_addr_set(CONNECTION_DOMAIN_INET, "127.0.0.1", 9050, 39 | &c_addr); 40 | ok(ret == 0 && 41 | c_addr.domain == CONNECTION_DOMAIN_INET && 42 | c_addr.u.sin.sin_family == AF_INET && 43 | c_addr.u.sin.sin_port == htons(9050), 44 | "Valid connection address creation"); 45 | 46 | conn = connection_create(42, (struct sockaddr *) &c_addr.u.sin); 47 | ok(conn && 48 | conn->fd == 42 && 49 | conn->dest_addr.domain == CONNECTION_DOMAIN_INET && 50 | conn->refcount.count == 1, 51 | "Valid connection creation"); 52 | if (!conn) { 53 | return; 54 | } 55 | 56 | conn2 = connection_create(43, (struct sockaddr *) &c_addr.u.sin); 57 | ok(conn2 && 58 | conn2->fd == 43 && 59 | conn2->dest_addr.domain == CONNECTION_DOMAIN_INET && 60 | conn2->refcount.count == 1, 61 | "Valid second connection creation"); 62 | if (!conn2) { 63 | return; 64 | } 65 | 66 | connection_registry_lock(); 67 | connection_insert(conn); 68 | l_conn = connection_find(conn->fd); 69 | ok(conn == l_conn, "Valid connection insert/find"); 70 | 71 | connection_insert(conn2); 72 | l_conn = connection_find(conn2->fd); 73 | ok(conn2 == l_conn, "Valid second connection insert/find"); 74 | 75 | connection_remove(conn); 76 | l_conn = connection_find(conn->fd); 77 | ok(conn != l_conn, "Valid connection remove/find"); 78 | 79 | connection_remove(conn2); 80 | l_conn = connection_find(conn2->fd); 81 | ok(conn2 != l_conn, "Valid second connection remove/find"); 82 | connection_registry_unlock(); 83 | 84 | connection_destroy(conn); 85 | connection_destroy(conn2); 86 | } 87 | 88 | static void test_connection_creation(void) 89 | { 90 | int ret; 91 | struct connection *conn; 92 | struct connection_addr c_addr; 93 | 94 | diag("Connection subsystem creation test"); 95 | 96 | ret = connection_addr_set(CONNECTION_DOMAIN_INET, "127.0.0.1", 9050, 97 | &c_addr); 98 | ok(ret == 0 && 99 | c_addr.domain == CONNECTION_DOMAIN_INET && 100 | c_addr.u.sin.sin_family == AF_INET && 101 | c_addr.u.sin.sin_port == htons(9050), 102 | "Valid connection address creation"); 103 | 104 | conn = connection_create(42, (struct sockaddr *) &c_addr.u.sin); 105 | ok(conn && 106 | conn->fd == 42 && 107 | conn->dest_addr.domain == CONNECTION_DOMAIN_INET && 108 | conn->refcount.count == 1, 109 | "Valid connection creation"); 110 | connection_destroy(conn); 111 | 112 | conn = connection_create(-1, (struct sockaddr *) &c_addr.u.sin); 113 | ok(conn && 114 | conn->fd == -1 && 115 | conn->dest_addr.domain == CONNECTION_DOMAIN_INET && 116 | conn->refcount.count == 1, 117 | "Valid connection creation with fd -1"); 118 | connection_destroy(conn); 119 | 120 | conn = connection_create(42, NULL); 121 | ok(conn && 122 | conn->fd == 42 && 123 | conn->dest_addr.domain == 0 && 124 | conn->refcount.count == 1, 125 | "Valid connection creation with sockaddr NULL"); 126 | connection_destroy(conn); 127 | 128 | ret = connection_addr_set(CONNECTION_DOMAIN_INET6, "::1", 9050, 129 | &c_addr); 130 | ok(ret == 0 && 131 | c_addr.domain == CONNECTION_DOMAIN_INET6 && 132 | c_addr.u.sin.sin_family == AF_INET6 && 133 | c_addr.u.sin.sin_port == htons(9050), 134 | "Valid connection address creation for IPv6"); 135 | 136 | conn = connection_create(42, (struct sockaddr *) &c_addr.u.sin6); 137 | ok(conn && 138 | conn->fd == 42 && 139 | conn->dest_addr.domain == CONNECTION_DOMAIN_INET6 && 140 | conn->refcount.count == 1, 141 | "Valid connection creation for IPv6"); 142 | connection_destroy(conn); 143 | } 144 | 145 | int main(int argc, char **argv) 146 | { 147 | /* Libtap call for the number of tests planned. */ 148 | plan_tests(NUM_TESTS); 149 | 150 | test_connection_creation(); 151 | test_connection_usage(); 152 | 153 | return 0; 154 | } 155 | -------------------------------------------------------------------------------- /tests/unit/test_onion.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 - David Goulet 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License, version 2 only, as 6 | * published by the Free Software Foundation. 7 | * 8 | * This program is distributed in the hope that it will be useful, but WITHOUT 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 | * more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along with 14 | * this program; if not, write to the Free Software Foundation, Inc., 51 15 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | #define NUM_TESTS 12 29 | 30 | static void test_onion_entry(struct onion_pool *pool) 31 | { 32 | int ret; 33 | struct onion_entry *entry; 34 | const char *onion_addr1 = "87idq6tnejk5plpn.onion"; 35 | const char *onion_addr2 = "97idq6tnejk5plpn.onion"; 36 | const char *onion_addr1_typo = "87idq6tnejk5plpn.onio"; 37 | struct sockaddr_in sin; 38 | 39 | diag("Onion entry subsystem initialization test"); 40 | 41 | /* Create valid onion pool from default values. */ 42 | ret = onion_pool_init(pool, inet_addr(DEFAULT_ONION_ADDR_RANGE), 43 | (uint8_t) atoi(DEFAULT_ONION_ADDR_MASK)); 44 | ok(ret == 0 && 45 | pool->base == 0 && 46 | pool->max_pos == 255 && 47 | pool->size == 8 && 48 | pool->count == 0 && 49 | pool->next_entry_pos == 0, 50 | "Valid onion pool created"); 51 | 52 | entry = onion_entry_create(pool, onion_addr1); 53 | ok(entry && 54 | pool->count == 1 && 55 | pool->next_entry_pos == 1 && 56 | strcmp(entry->hostname, onion_addr1) == 0 && 57 | strcmp(DEFAULT_ONION_ADDR_RANGE, 58 | inet_ntoa(*((struct in_addr *) &entry->ip))) == 0, 59 | "Valid onion entry %s created", onion_addr1); 60 | 61 | entry = onion_entry_find_by_name("meh", pool); 62 | ok(!entry, "Onion entry not found"); 63 | 64 | entry = onion_entry_find_by_name(onion_addr1_typo, pool); 65 | ok(!entry, "Onion entry with typo not found"); 66 | 67 | entry = onion_entry_find_by_name(onion_addr1, pool); 68 | ok(entry && 69 | pool->count == 1 && 70 | strcmp(entry->hostname, onion_addr1) == 0 && 71 | strcmp(DEFAULT_ONION_ADDR_RANGE, 72 | inet_ntoa(*((struct in_addr *) &entry->ip))) == 0, 73 | "Valid onion entry found by name"); 74 | 75 | sin.sin_family = AF_INET; 76 | sin.sin_addr.s_addr = inet_addr(DEFAULT_ONION_ADDR_RANGE); 77 | entry = onion_entry_find_by_addr((const struct sockaddr *) &sin, pool); 78 | ok(entry && 79 | pool->count == 1 && 80 | strcmp(entry->hostname, onion_addr1) == 0 && 81 | strcmp(DEFAULT_ONION_ADDR_RANGE, 82 | inet_ntoa(*((struct in_addr *) &entry->ip))) == 0, 83 | "Valid onion entry found by IP"); 84 | 85 | entry = onion_entry_create(pool, onion_addr2); 86 | ok(entry && 87 | pool->count == 2 && 88 | pool->next_entry_pos == 2 && 89 | strcmp(entry->hostname, onion_addr2) == 0 && 90 | strcmp("127.42.42.1", 91 | inet_ntoa(*((struct in_addr *) &entry->ip))) == 0, 92 | "Valid onion entry %s created", onion_addr2); 93 | 94 | onion_pool_destroy(pool); 95 | } 96 | 97 | static void test_onion_init(struct onion_pool *pool) 98 | { 99 | int ret; 100 | uint8_t mask; 101 | in_addr_t base; 102 | 103 | diag("Onion subsystem initialization test"); 104 | 105 | /* Valid default configuration test. */ 106 | base = inet_addr(DEFAULT_ONION_ADDR_RANGE); 107 | mask = (uint8_t) atoi(DEFAULT_ONION_ADDR_MASK); 108 | ret = onion_pool_init(pool, base, mask); 109 | ok(ret == 0 && 110 | pool->entries && 111 | pool->base == 0 && 112 | pool->max_pos == 255 && 113 | pool->size == 8 && 114 | pool->count == 0 && 115 | pool->next_entry_pos == 0, 116 | "Valid onion pool of %s/%d", DEFAULT_ONION_ADDR_RANGE, mask); 117 | onion_pool_destroy(pool); 118 | 119 | /* Valid test. */ 120 | base = inet_addr("127.42.42.64"); 121 | mask = 27; 122 | ret = onion_pool_init(pool, base, mask); 123 | ok(ret == 0 && 124 | pool->entries && 125 | pool->base == 64 && 126 | pool->max_pos == 95 && 127 | pool->size == 8 && 128 | pool->count == 0 && 129 | pool->next_entry_pos == 0, 130 | "Valid onion pool of 127.42.42.64/27"); 131 | onion_pool_destroy(pool); 132 | 133 | /* Valid test. */ 134 | base = inet_addr("127.42.42.64"); 135 | mask = 17; 136 | ret = onion_pool_init(pool, base, mask); 137 | ok(ret == 0 && 138 | pool->entries && 139 | pool->base == 0 && 140 | pool->max_pos == 32767 && 141 | pool->size == 8 && 142 | pool->count == 0 && 143 | pool->next_entry_pos == 0, 144 | "Valid onion pool of 127.42.42.64/17"); 145 | onion_pool_destroy(pool); 146 | 147 | /* Valid test with size less than default. */ 148 | base = inet_addr("127.42.42.0"); 149 | mask = 32; 150 | ret = onion_pool_init(pool, base, mask); 151 | ok(ret == 0 && 152 | pool->entries && 153 | pool->base == 0 && 154 | pool->max_pos == 0 && 155 | pool->size == 1 && 156 | pool->count == 0 && 157 | pool->next_entry_pos == 0, 158 | "Valid onion pool of 127.42.42.0/32"); 159 | onion_pool_destroy(pool); 160 | 161 | /* Invalid test. */ 162 | base = inet_addr("127.42.42.64"); 163 | mask = 42; 164 | ret = onion_pool_init(pool, base, mask); 165 | ok(ret == -EINVAL, 166 | "Invalid onion pool of mask 42"); 167 | } 168 | 169 | int main(int argc, char **argv) 170 | { 171 | struct onion_pool pool; 172 | 173 | /* Libtap call for the number of tests planned. */ 174 | plan_tests(NUM_TESTS); 175 | 176 | test_onion_init(&pool); 177 | test_onion_entry(&pool); 178 | 179 | return 0; 180 | } 181 | -------------------------------------------------------------------------------- /tests/unit/test_utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2013 - David Goulet 3 | * Luke Gallagher 4 | * 5 | * This program is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU General Public License, version 2 only, as 7 | * published by the Free Software Foundation. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 | * more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along with 15 | * this program; if not, write to the Free Software Foundation, Inc., 51 16 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | #define NUM_TESTS 31 28 | 29 | static void test_is_address_ipv4(void) 30 | { 31 | int ret = 0; 32 | 33 | diag("Utils IPv4 test"); 34 | 35 | ret = utils_is_address_ipv4("127.0.0.1"); 36 | ok(ret == 1, "Valid IPv4 address"); 37 | 38 | ret = utils_is_address_ipv4("127.0.0.256"); 39 | ok(ret == 0, "Invalid IPv4 address"); 40 | 41 | ret = utils_is_address_ipv4("::1"); 42 | ok(ret == 0, "Invalid IPv4 address when IPv6"); 43 | } 44 | 45 | static void test_is_address_ipv6(void) 46 | { 47 | int ret = 0; 48 | 49 | diag("Utils IPv6 test"); 50 | 51 | ret = utils_is_address_ipv6("::1"); 52 | ok(ret == 1, "Valid IPv6 address"); 53 | 54 | ret = utils_is_address_ipv6("2001:DB8:0:0:8:800:200C:417A"); 55 | ok(ret == 1, "Valid IPv6 address"); 56 | 57 | ret = utils_is_address_ipv6("2001:DB8:0:0:8:800:200C:G"); 58 | ok(ret == 0, "Invalid IPv6 address"); 59 | 60 | ret = utils_is_address_ipv6("192.168.0.1"); 61 | ok(ret == 0, "Invalid IPv6 address when IPv4"); 62 | } 63 | 64 | static void test_localhost_resolve(void) 65 | { 66 | int ret = 0; 67 | in_addr_t ipv4, loopback = htonl(TSOCKS_LOOPBACK); 68 | struct in6_addr ipv6; 69 | const uint8_t loopback6[] = TSOCKS_LOOPBACK6; 70 | 71 | diag("Utils localhost resolve test"); 72 | 73 | ret = utils_localhost_resolve("localhost", AF_INET, &ipv4, sizeof(ipv4)); 74 | ok(ret == 1, "localhost resolved successfully"); 75 | ok(memcmp(&ipv4, &loopback, sizeof(ipv4)) == 0, 76 | "localhost IPv4 address matches"); 77 | 78 | ret = utils_localhost_resolve("ip-localhost", AF_INET, &ipv4, sizeof(ipv4)); 79 | ok(ret == 1, "ip-localhost resolved successfully"); 80 | ok(memcmp(&ipv4, &loopback, sizeof(ipv4)) == 0, 81 | "ip-localhost IPv4 address matches"); 82 | 83 | ret = utils_localhost_resolve("nsa.gov", AF_INET, &ipv4, sizeof(ipv4)); 84 | ok(ret == 0, "nsa.gov did NOT resolved successfully"); 85 | 86 | /* Len smaller than buffer size. */ 87 | ret = utils_localhost_resolve("localhost", AF_INET, &ipv4, 1); 88 | ok(ret == -EINVAL, "localhost len of buffer was too small"); 89 | 90 | /* IPV6 */ 91 | 92 | ret = utils_localhost_resolve("localhost", AF_INET6, &ipv6, sizeof(ipv6)); 93 | ok(ret == 1, "localhost v6 resolved successfully"); 94 | ok(memcmp(&ipv6, &loopback6, sizeof(in6addr_loopback)) == 0, 95 | "localhost IPv6 address matches"); 96 | 97 | ret = utils_localhost_resolve("ip6-localhost", AF_INET6, &ipv6, 98 | sizeof(ipv6)); 99 | ok(ret == 1, "ip6-localhost resolved successfully"); 100 | ok(memcmp(&ipv6, &loopback6, sizeof(in6addr_loopback)) == 0, 101 | "localhost IPv6 address matches"); 102 | 103 | ret = utils_localhost_resolve("nsa.gov", AF_INET6, &ipv6, sizeof(ipv6)); 104 | ok(ret == 0, "nsa.gov did NOT resolved successfully"); 105 | 106 | /* Len smaller than buffer size. */ 107 | ret = utils_localhost_resolve("localhost", AF_INET6, &ipv6, 1); 108 | ok(ret == -EINVAL, "localhost v6 len of buffer was too small"); 109 | } 110 | 111 | static void test_sockaddr_is_localhost(void) 112 | { 113 | int ret; 114 | struct sockaddr_in sin; 115 | struct sockaddr_in6 sin6; 116 | 117 | diag("Utils sockaddr is localhost"); 118 | 119 | sin.sin_family = AF_INET; 120 | sin.sin_addr.s_addr = htonl(TSOCKS_LOOPBACK); 121 | ret = utils_sockaddr_is_localhost((const struct sockaddr *) &sin); 122 | ok(ret == 1, "Loopback matches localhost"); 123 | 124 | (void) inet_pton(sin.sin_family, "127.8.42.42", &sin.sin_addr.s_addr); 125 | ret = utils_sockaddr_is_localhost((const struct sockaddr *) &sin); 126 | ok(ret == 1, "127.8.42.42 matches localhost"); 127 | 128 | (void) inet_pton(sin.sin_family, "128.8.42.42", &sin.sin_addr.s_addr); 129 | ret = utils_sockaddr_is_localhost((const struct sockaddr *) &sin); 130 | ok(ret == 0, "128.8.42.42 does NO match localhost"); 131 | 132 | /* IPv6 */ 133 | 134 | sin6.sin6_family = AF_INET6; 135 | (void) inet_pton(sin6.sin6_family, "::1", &sin6.sin6_addr.s6_addr); 136 | ret = utils_sockaddr_is_localhost((const struct sockaddr *) &sin6); 137 | ok(ret == 1, "::1 matches localhost"); 138 | } 139 | 140 | static void helper_reset_tokens(char **tokens) 141 | { 142 | assert(tokens); 143 | 144 | int i; 145 | for (i = 0; i < DEFAULT_MAX_CONF_TOKEN; i++) { 146 | tokens[i] = NULL; 147 | } 148 | } 149 | 150 | static void test_utils_tokenize_ignore_comments(void) 151 | { 152 | int nb_token; 153 | char line[BUFSIZ]; 154 | char *tokens[DEFAULT_MAX_CONF_TOKEN]; 155 | 156 | diag("Utils tokenize line test"); 157 | 158 | helper_reset_tokens(tokens); 159 | strcpy(line, "a\tb"); 160 | nb_token = utils_tokenize_ignore_comments(line, sizeof(tokens), tokens); 161 | ok(nb_token == 2 && 162 | (0 == strcmp(tokens[0], "a")) && 163 | (0 == strcmp(tokens[1], "b")), 164 | "Returns 2 tokens"); 165 | 166 | helper_reset_tokens(tokens); 167 | strcpy(line, "foo bar"); 168 | nb_token = utils_tokenize_ignore_comments(line, sizeof(tokens), tokens); 169 | ok(nb_token == 2 && 170 | (0 == strcmp(tokens[0], "foo")) && 171 | (0 == strcmp(tokens[1], "bar")), 172 | "Returns 2 tokens"); 173 | 174 | helper_reset_tokens(tokens); 175 | strcpy(line, "a b c"); 176 | nb_token = utils_tokenize_ignore_comments(line, sizeof(tokens), tokens); 177 | ok(nb_token == 3 && 178 | (0 == strcmp(tokens[0], "a")) && 179 | (0 == strcmp(tokens[1], "b")) && 180 | (0 == strcmp(tokens[2], "c")), 181 | "Returns 3 tokens"); 182 | 183 | helper_reset_tokens(tokens); 184 | strcpy(line, "# this is a comment"); 185 | nb_token = utils_tokenize_ignore_comments(line, sizeof(tokens), tokens); 186 | ok(nb_token == 0, "Returns 0 tokens for comment"); 187 | } 188 | 189 | static void test_is_addr_any(void) 190 | { 191 | int ret; 192 | struct sockaddr_in sin; 193 | struct sockaddr_in6 sin6; 194 | 195 | sin.sin_family = AF_INET; 196 | sin.sin_port = htons(42); 197 | inet_pton(sin.sin_family, "0.0.0.0", &sin.sin_addr); 198 | 199 | ret = utils_is_addr_any((const struct sockaddr *) &sin); 200 | ok(ret == 1, "This address is 0.0.0.0"); 201 | 202 | sin.sin_family = AF_INET; 203 | sin.sin_port = htons(42); 204 | inet_pton(sin.sin_family, "1.0.0.0", &sin.sin_addr); 205 | 206 | ret = utils_is_addr_any((const struct sockaddr *) &sin); 207 | ok(ret == 0, "This address is NOT 0.0.0.0"); 208 | 209 | sin6.sin6_family = AF_INET6; 210 | sin6.sin6_port = htons(42); 211 | inet_pton(sin6.sin6_family, "::", &sin6.sin6_addr); 212 | 213 | ret = utils_is_addr_any((const struct sockaddr *) &sin6); 214 | ok(ret == 1, "This address is ::"); 215 | 216 | sin6.sin6_family = AF_INET6; 217 | sin6.sin6_port = htons(42); 218 | inet_pton(sin6.sin6_family, "fe80::1", &sin6.sin6_addr); 219 | 220 | ret = utils_is_addr_any((const struct sockaddr *) &sin6); 221 | ok(ret == 0, "This address is NOT ::"); 222 | } 223 | 224 | int main(int argc, char **argv) 225 | { 226 | /* Libtap call for the number of tests planned. */ 227 | plan_tests(NUM_TESTS); 228 | 229 | test_is_address_ipv4(); 230 | test_is_address_ipv6(); 231 | test_localhost_resolve(); 232 | test_sockaddr_is_localhost(); 233 | test_utils_tokenize_ignore_comments(); 234 | test_is_addr_any(); 235 | 236 | return exit_status(); 237 | } 238 | -------------------------------------------------------------------------------- /tests/utils/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = tap 2 | 3 | EXTRA_DIST = fixtures.h 4 | -------------------------------------------------------------------------------- /tests/utils/fixtures.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2000-2008 - Shaun Clowes 3 | * 2008-2011 - Robert Hogan 4 | * 2013 - David Goulet 5 | * Luke Gallagher 6 | * 7 | * This program is free software; you can redistribute it and/or modify it 8 | * under the terms of the GNU General Public License, version 2 only, as 9 | * published by the Free Software Foundation. 10 | * 11 | * This program is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 14 | * more details. 15 | * 16 | * You should have received a copy of the GNU General Public License along with 17 | * this program; if not, write to the Free Software Foundation, Inc., 51 18 | * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | */ 20 | 21 | #ifndef FIXTURES_H 22 | #define FIXTURES_H 23 | 24 | #include 25 | 26 | #if !defined(TORSOCKS_FIXTURE_PATH) 27 | #define TORSOCKS_FIXTURE_PATH 0 28 | #endif /* TORSOCKS_FIXTURE_PATH */ 29 | 30 | static const char *fixture_path(const char *base, const char *filename) 31 | { 32 | static char path[1024]; 33 | size_t path_len; 34 | 35 | path_len = strlen(base); 36 | strncpy(path, base, path_len); 37 | strncpy(path + path_len, filename, sizeof(path) - path_len); 38 | 39 | return path; 40 | } 41 | 42 | const char *fixture(const char *fixture_name) 43 | { 44 | return fixture_path(TORSOCKS_FIXTURE_PATH, fixture_name); 45 | } 46 | 47 | #endif /* FIXTURES_H */ 48 | -------------------------------------------------------------------------------- /tests/utils/tap/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_LTLIBRARIES = libtap.la 2 | libtap_la_SOURCES = tap.c tap.h 3 | dist_noinst_SCRIPTS = tap.sh 4 | EXTRA_DIST = tap.sh 5 | -------------------------------------------------------------------------------- /tests/utils/tap/tap.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2004 Nik Clayton 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | */ 26 | 27 | /* '## __VA_ARGS__' is a gcc'ism. C99 doesn't allow the token pasting 28 | and requires the caller to add the final comma if they've ommitted 29 | the optional arguments */ 30 | #ifdef __GNUC__ 31 | # define ok(e, test, ...) ((e) ? \ 32 | _gen_result(1, __func__, __FILE__, __LINE__, \ 33 | test, ## __VA_ARGS__) : \ 34 | _gen_result(0, __func__, __FILE__, __LINE__, \ 35 | test, ## __VA_ARGS__)) 36 | 37 | # define ok1(e) ((e) ? \ 38 | _gen_result(1, __func__, __FILE__, __LINE__, "%s", #e) : \ 39 | _gen_result(0, __func__, __FILE__, __LINE__, "%s", #e)) 40 | 41 | # define pass(test, ...) ok(1, test, ## __VA_ARGS__); 42 | # define fail(test, ...) ok(0, test, ## __VA_ARGS__); 43 | 44 | # define skip_start(test, n, fmt, ...) \ 45 | do { \ 46 | if((test)) { \ 47 | skip(n, fmt, ## __VA_ARGS__); \ 48 | continue; \ 49 | } 50 | #elif __STDC_VERSION__ >= 199901L /* __GNUC__ */ 51 | # define ok(e, ...) ((e) ? \ 52 | _gen_result(1, __func__, __FILE__, __LINE__, \ 53 | __VA_ARGS__) : \ 54 | _gen_result(0, __func__, __FILE__, __LINE__, \ 55 | __VA_ARGS__)) 56 | 57 | # define ok1(e) ((e) ? \ 58 | _gen_result(1, __func__, __FILE__, __LINE__, "%s", #e) : \ 59 | _gen_result(0, __func__, __FILE__, __LINE__, "%s", #e)) 60 | 61 | # define pass(...) ok(1, __VA_ARGS__); 62 | # define fail(...) ok(0, __VA_ARGS__); 63 | 64 | # define skip_start(test, n, ...) \ 65 | do { \ 66 | if((test)) { \ 67 | skip(n, __VA_ARGS__); \ 68 | continue; \ 69 | } 70 | #else /* __STDC_VERSION__ */ 71 | # error "Needs gcc or C99 compiler for variadic macros." 72 | #endif /* __STDC_VERSION__ */ 73 | 74 | #define skip_end() } while(0); 75 | 76 | unsigned int _gen_result(int, const char *, char *, unsigned int, char *, ...); 77 | 78 | int plan_no_plan(void); 79 | int plan_skip_all(char *); 80 | int plan_tests(unsigned int); 81 | 82 | unsigned int diag(char *, ...); 83 | 84 | int skip(unsigned int, char *, ...); 85 | 86 | void todo_start(char *, ...); 87 | void todo_end(void); 88 | 89 | int exit_status(void); 90 | --------------------------------------------------------------------------------