2011-02-25 17:40:11 +08:00
/***************************************************************************
libproxychains . c - description
- - - - - - - - - - - - - - - - - - -
begin : Tue May 14 2002
copyright : netcreature ( C ) 2002
email : netcreature @ users . sourceforge . net
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* GPL */
/***************************************************************************
* *
* This program is free software ; you can redistribute it and / or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation ; either version 2 of the License , or *
* ( at your option ) any later version . *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-09-04 07:45:16 +08:00
# undef _GNU_SOURCE
2011-02-25 17:40:11 +08:00
# define _GNU_SOURCE
2011-09-04 07:45:16 +08:00
2011-02-25 17:40:11 +08:00
# include <stdio.h>
# include <unistd.h>
# include <stdlib.h>
2011-09-03 01:55:50 +08:00
# include <string.h>
2011-02-25 17:40:11 +08:00
# include <errno.h>
2012-11-07 23:49:14 +08:00
# include <assert.h>
2011-02-25 17:40:11 +08:00
# include <netdb.h>
# include <netinet/in.h>
# include <arpa/inet.h>
# include <sys/types.h>
# include <sys/socket.h>
2011-09-03 01:55:50 +08:00
# include <fcntl.h>
2011-02-25 17:40:11 +08:00
# include <dlfcn.h>
2012-11-08 04:28:09 +08:00
# include <pthread.h>
2011-02-25 17:40:11 +08:00
# include "core.h"
2011-09-11 04:32:27 +08:00
# include "common.h"
2011-02-25 17:40:11 +08:00
2020-08-17 16:31:04 +08:00
# undef satosin
2011-02-25 17:40:11 +08:00
# define satosin(x) ((struct sockaddr_in *) &(x))
# define SOCKADDR(x) (satosin(x)->sin_addr.s_addr)
# define SOCKADDR_2(x) (satosin(x)->sin_addr)
# define SOCKPORT(x) (satosin(x)->sin_port)
# define SOCKFAMILY(x) (satosin(x)->sin_family)
2012-04-24 07:48:17 +08:00
# define MAX_CHAIN 512
2011-02-25 17:40:11 +08:00
2018-01-11 01:23:36 +08:00
# ifdef IS_SOLARIS
# undef connect
int __xnet_connect ( int sock , const struct sockaddr * addr , unsigned int len ) ;
connect_t true___xnet_connect ;
# endif
2013-01-21 08:54:45 +08:00
close_t true_close ;
2012-07-08 06:16:00 +08:00
connect_t true_connect ;
gethostbyname_t true_gethostbyname ;
getaddrinfo_t true_getaddrinfo ;
freeaddrinfo_t true_freeaddrinfo ;
getnameinfo_t true_getnameinfo ;
gethostbyaddr_t true_gethostbyaddr ;
2015-01-24 00:14:28 +08:00
sendto_t true_sendto ;
2012-07-08 06:16:00 +08:00
2011-02-25 17:40:11 +08:00
int tcp_read_time_out ;
int tcp_connect_time_out ;
chain_type proxychains_ct ;
proxy_data proxychains_pd [ MAX_CHAIN ] ;
2011-09-04 07:45:16 +08:00
unsigned int proxychains_proxy_count = 0 ;
2013-06-23 13:13:40 +08:00
unsigned int proxychains_proxy_offset = 0 ;
2011-02-25 17:40:11 +08:00
int proxychains_got_chain_data = 0 ;
2011-09-04 07:45:16 +08:00
unsigned int proxychains_max_chain = 1 ;
2011-02-25 17:40:11 +08:00
int proxychains_quiet_mode = 0 ;
int proxychains_resolver = 0 ;
2011-02-25 23:16:58 +08:00
localaddr_arg localnet_addr [ MAX_LOCALNET ] ;
size_t num_localnet_addr = 0 ;
2020-05-06 05:33:42 +08:00
dnat_arg dnats [ MAX_DNAT ] ;
size_t num_dnats = 0 ;
2012-01-26 19:44:42 +08:00
unsigned int remote_dns_subnet = 224 ;
2011-02-25 23:16:58 +08:00
2012-04-24 04:14:04 +08:00
pthread_once_t init_once = PTHREAD_ONCE_INIT ;
2012-11-08 04:28:09 +08:00
2012-04-24 04:14:04 +08:00
static int init_l = 0 ;
2019-02-28 21:28:10 +08:00
static void get_chain_data ( proxy_data * pd , unsigned int * proxy_count , chain_type * ct ) ;
2011-02-25 17:40:11 +08:00
2012-07-08 06:27:46 +08:00
static void * load_sym ( char * symname , void * proxyfunc ) {
2012-01-28 00:55:37 +08:00
2012-07-08 06:27:46 +08:00
void * funcptr = dlsym ( RTLD_NEXT , symname ) ;
2014-07-21 19:18:20 +08:00
2012-07-08 06:27:46 +08:00
if ( ! funcptr ) {
2012-04-24 01:51:14 +08:00
fprintf ( stderr , " Cannot load symbol '%s' %s \n " , symname , dlerror ( ) ) ;
2011-02-25 17:40:11 +08:00
exit ( 1 ) ;
} else {
2012-07-08 10:09:50 +08:00
PDEBUG ( " loaded symbol '%s' " " real addr %p wrapped addr %p \n " , symname , funcptr , proxyfunc ) ;
2011-02-25 17:40:11 +08:00
}
2012-07-08 06:27:46 +08:00
if ( funcptr = = proxyfunc ) {
2011-09-04 07:45:16 +08:00
PDEBUG ( " circular reference detected, aborting! \n " ) ;
abort ( ) ;
}
2012-07-08 06:27:46 +08:00
return funcptr ;
2012-04-24 01:51:14 +08:00
}
2012-01-28 00:55:37 +08:00
2012-04-24 04:14:04 +08:00
# define INIT() init_lib_wrapper(__FUNCTION__)
2016-05-26 17:48:32 +08:00
# define SETUP_SYM(X) do { if (! true_ ## X ) true_ ## X = load_sym( # X, X ); } while(0)
2012-07-08 06:27:46 +08:00
2012-11-07 23:49:14 +08:00
# include "allocator_thread.h"
2014-07-22 20:10:08 +08:00
const char * proxychains_get_version ( void ) ;
2015-12-02 20:14:58 +08:00
static void setup_hooks ( void ) {
SETUP_SYM ( connect ) ;
SETUP_SYM ( sendto ) ;
SETUP_SYM ( gethostbyname ) ;
SETUP_SYM ( getaddrinfo ) ;
SETUP_SYM ( freeaddrinfo ) ;
SETUP_SYM ( gethostbyaddr ) ;
SETUP_SYM ( getnameinfo ) ;
2018-01-11 01:23:36 +08:00
# ifdef IS_SOLARIS
SETUP_SYM ( __xnet_connect ) ;
# endif
2020-09-21 00:03:54 +08:00
SETUP_SYM ( close ) ;
2015-12-02 20:14:58 +08:00
}
2016-05-27 02:01:14 +08:00
static int close_fds [ 16 ] ;
static int close_fds_cnt = 0 ;
2020-09-21 00:03:54 +08:00
static void rdns_init ( void ) {
at_init ( ) ;
}
2012-04-24 04:14:04 +08:00
static void do_init ( void ) {
2012-11-08 03:11:14 +08:00
srand ( time ( NULL ) ) ;
2012-11-08 04:28:09 +08:00
core_initialize ( ) ;
2014-07-21 19:18:20 +08:00
2012-04-24 01:51:14 +08:00
/* read the config file */
get_chain_data ( proxychains_pd , & proxychains_proxy_count , & proxychains_ct ) ;
2013-06-23 13:13:40 +08:00
DUMP_PROXY_CHAIN ( proxychains_pd , proxychains_proxy_count ) ;
2011-02-25 17:40:11 +08:00
2014-07-22 20:10:08 +08:00
proxychains_write_log ( LOG_PREFIX " DLL init: proxychains-ng %s \n " , proxychains_get_version ( ) ) ;
2014-07-21 19:18:20 +08:00
2015-12-02 20:14:58 +08:00
setup_hooks ( ) ;
2014-07-21 19:18:20 +08:00
2016-05-27 02:01:14 +08:00
while ( close_fds_cnt ) true_close ( close_fds [ - - close_fds_cnt ] ) ;
2011-02-25 17:40:11 +08:00
init_l = 1 ;
2020-09-21 00:03:54 +08:00
if ( proxychains_resolver ) rdns_init ( ) ;
2011-02-25 17:40:11 +08:00
}
2012-04-24 04:14:04 +08:00
static void init_lib_wrapper ( const char * caller ) {
# ifndef DEBUG
( void ) caller ;
# endif
if ( ! init_l ) PDEBUG ( " %s called from %s \n " , __FUNCTION__ , caller ) ;
pthread_once ( & init_once , do_init ) ;
}
/* if we use gcc >= 3, we can instruct the dynamic loader
* to call init_lib at link time . otherwise it gets loaded
* lazily , which has the disadvantage that there ' s a potential
* race condition if 2 threads call it before init_l is set
* and PTHREAD support was disabled */
# if __GNUC__ > 2
__attribute__ ( ( constructor ) )
static void gcc_init ( void ) {
INIT ( ) ;
}
# endif
2018-07-27 06:12:00 +08:00
typedef enum {
RS_PT_NONE = 0 ,
RS_PT_SOCKS4 ,
RS_PT_SOCKS5 ,
RS_PT_HTTP
} rs_proxyType ;
/*
proxy_from_string ( ) taken from rocksock network I / O library ( C ) rofl0r
valid inputs :
socks5 : //user:password@proxy.domain.com:port
socks5 : //proxy.domain.com:port
socks4 : //proxy.domain.com:port
http : //user:password@proxy.domain.com:port
http : //proxy.domain.com:port
supplying port number is obligatory .
user : pass @ part is optional for http and socks5 .
however , user : pass authentication is currently not implemented for http proxies .
return 1 on success , 0 on error .
*/
static int proxy_from_string ( const char * proxystring ,
char * type_buf ,
char * host_buf ,
int * port_n ,
char * user_buf ,
char * pass_buf )
{
const char * p ;
rs_proxyType proxytype ;
size_t next_token = 6 , ul = 0 , pl = 0 , hl ;
if ( ! proxystring [ 0 ] | | ! proxystring [ 1 ] | | ! proxystring [ 2 ] | | ! proxystring [ 3 ] | | ! proxystring [ 4 ] | | ! proxystring [ 5 ] ) goto inv_string ;
if ( * proxystring = = ' s ' ) {
switch ( proxystring [ 5 ] ) {
case ' 5 ' : proxytype = RS_PT_SOCKS5 ; break ;
case ' 4 ' : proxytype = RS_PT_SOCKS4 ; break ;
default : goto inv_string ;
}
} else if ( * proxystring = = ' h ' ) {
proxytype = RS_PT_HTTP ;
next_token = 4 ;
} else goto inv_string ;
if (
proxystring [ next_token + + ] ! = ' : ' | |
proxystring [ next_token + + ] ! = ' / ' | |
proxystring [ next_token + + ] ! = ' / ' ) goto inv_string ;
2019-04-21 08:48:35 +08:00
const char * at = strrchr ( proxystring + next_token , ' @ ' ) ;
2018-07-27 06:12:00 +08:00
if ( at ) {
if ( proxytype = = RS_PT_SOCKS4 )
return 0 ;
p = strchr ( proxystring + next_token , ' : ' ) ;
if ( ! p | | p > = at ) goto inv_string ;
const char * u = proxystring + next_token ;
ul = p - u ;
p + + ;
pl = at - p ;
if ( proxytype = = RS_PT_SOCKS5 & & ( ul > 255 | | pl > 255 ) )
return 0 ;
memcpy ( user_buf , u , ul ) ;
user_buf [ ul ] = 0 ;
memcpy ( pass_buf , p , pl ) ;
pass_buf [ pl ] = 0 ;
next_token + = 2 + ul + pl ;
} else {
user_buf [ 0 ] = 0 ;
pass_buf [ 0 ] = 0 ;
}
const char * h = proxystring + next_token ;
p = strchr ( h , ' : ' ) ;
if ( ! p ) goto inv_string ;
hl = p - h ;
if ( hl > 255 )
return 0 ;
memcpy ( host_buf , h , hl ) ;
host_buf [ hl ] = 0 ;
* port_n = atoi ( p + 1 ) ;
switch ( proxytype ) {
case RS_PT_SOCKS4 :
strcpy ( type_buf , " socks4 " ) ;
break ;
case RS_PT_SOCKS5 :
strcpy ( type_buf , " socks5 " ) ;
break ;
case RS_PT_HTTP :
strcpy ( type_buf , " http " ) ;
break ;
default :
return 0 ;
}
return 1 ;
inv_string :
return 0 ;
}
2019-02-28 22:07:08 +08:00
static const char * bool_str ( int bool_val ) {
if ( bool_val ) return " true " ;
return " false " ;
}
2018-07-27 06:12:00 +08:00
2012-04-24 04:14:04 +08:00
/* get configuration from config file */
static void get_chain_data ( proxy_data * pd , unsigned int * proxy_count , chain_type * ct ) {
2012-01-28 01:59:44 +08:00
int count = 0 , port_n = 0 , list = 0 ;
char buff [ 1024 ] , type [ 1024 ] , host [ 1024 ] , user [ 1024 ] ;
2011-02-25 20:21:34 +08:00
char * env ;
2011-03-22 22:04:52 +08:00
char local_in_addr_port [ 32 ] ;
char local_in_addr [ 32 ] , local_in_port [ 32 ] , local_netmask [ 32 ] ;
2020-05-06 05:33:42 +08:00
char dnat_orig_addr_port [ 32 ] , dnat_new_addr_port [ 32 ] ;
char dnat_orig_addr [ 32 ] , dnat_orig_port [ 32 ] , dnat_new_addr [ 32 ] , dnat_new_port [ 32 ] ;
2012-07-09 05:32:50 +08:00
FILE * file = NULL ;
2011-02-25 17:40:11 +08:00
if ( proxychains_got_chain_data )
2012-01-28 01:59:44 +08:00
return ;
2011-02-25 17:40:11 +08:00
2020-09-21 00:02:21 +08:00
PFUNC ( ) ;
2011-02-25 17:40:11 +08:00
//Some defaults
2012-01-28 01:59:44 +08:00
tcp_read_time_out = 4 * 1000 ;
tcp_connect_time_out = 10 * 1000 ;
2011-09-04 07:45:16 +08:00
* ct = DYNAMIC_TYPE ;
2014-07-21 19:18:20 +08:00
2012-07-09 05:47:56 +08:00
env = get_config_path ( getenv ( PROXYCHAINS_CONF_FILE_ENV_VAR ) , buff , sizeof ( buff ) ) ;
2013-04-30 16:06:36 +08:00
if ( ( file = fopen ( env , " r " ) ) = = NULL )
{
perror ( " couldnt read configuration file " ) ;
exit ( 1 ) ;
}
2012-01-28 00:55:37 +08:00
2012-01-24 15:26:37 +08:00
env = getenv ( PROXYCHAINS_QUIET_MODE_ENV_VAR ) ;
2012-01-28 01:59:44 +08:00
if ( env & & * env = = ' 1 ' )
proxychains_quiet_mode = 1 ;
2011-02-25 17:40:11 +08:00
2012-01-28 01:59:44 +08:00
while ( fgets ( buff , sizeof ( buff ) , file ) ) {
if ( buff [ 0 ] ! = ' \n ' & & buff [ strspn ( buff , " " ) ] ! = ' # ' ) {
2012-04-24 08:04:02 +08:00
/* proxylist has to come last */
2011-02-25 17:40:11 +08:00
if ( list ) {
2012-04-24 08:04:02 +08:00
if ( count > = MAX_CHAIN )
break ;
2014-07-21 19:18:20 +08:00
2011-09-03 01:55:50 +08:00
memset ( & pd [ count ] , 0 , sizeof ( proxy_data ) ) ;
2012-01-28 00:55:37 +08:00
2011-11-06 21:12:50 +08:00
pd [ count ] . ps = PLAY_STATE ;
port_n = 0 ;
2012-01-28 00:55:37 +08:00
2014-07-21 19:17:24 +08:00
int ret = sscanf ( buff , " %s %s %d %s %s " , type , host , & port_n , pd [ count ] . user , pd [ count ] . pass ) ;
if ( ret < 3 | | ret = = EOF ) {
2018-07-27 06:12:00 +08:00
if ( ! proxy_from_string ( buff , type , host , & port_n , pd [ count ] . user , pd [ count ] . pass ) ) {
inv :
fprintf ( stderr , " error: invalid item in proxylist section: %s " , buff ) ;
exit ( 1 ) ;
}
2014-07-21 19:17:24 +08:00
}
2012-01-28 00:55:37 +08:00
2015-08-10 23:59:31 +08:00
memset ( & pd [ count ] . ip , 0 , sizeof ( pd [ count ] . ip ) ) ;
pd [ count ] . ip . is_v6 = ! ! strchr ( host , ' : ' ) ;
pd [ count ] . port = htons ( ( unsigned short ) port_n ) ;
ip_type * host_ip = & pd [ count ] . ip ;
if ( 1 ! = inet_pton ( host_ip - > is_v6 ? AF_INET6 : AF_INET , host , host_ip - > addr . v6 ) ) {
2019-02-28 22:07:08 +08:00
if ( * ct = = STRICT_TYPE & & proxychains_resolver & & count > 0 ) {
/* we can allow dns hostnames for all but the first proxy in the list if chaintype is strict, as remote lookup can be done */
ip_type4 internal_ip = at_get_ip_for_host ( host , strlen ( host ) ) ;
pd [ count ] . ip . is_v6 = 0 ;
host_ip - > addr . v4 = internal_ip ;
if ( internal_ip . as_int = = ip_type_invalid . addr . v4 . as_int )
goto inv_host ;
} else {
inv_host :
fprintf ( stderr , " proxy %s has invalid value or is not numeric \n " , host ) ;
fprintf ( stderr , " non-numeric ips are only allowed under the following circumstances: \n " ) ;
fprintf ( stderr , " chaintype == strict (%s), proxy is not first in list (%s), proxy_dns active (%s) \n \n " , bool_str ( * ct = = STRICT_TYPE ) , bool_str ( count > 0 ) , bool_str ( proxychains_resolver ) ) ;
exit ( 1 ) ;
}
2013-05-02 19:40:56 +08:00
}
2012-01-28 00:55:37 +08:00
2012-01-28 01:59:44 +08:00
if ( ! strcmp ( type , " http " ) ) {
2011-11-06 21:12:50 +08:00
pd [ count ] . pt = HTTP_TYPE ;
2012-01-28 01:59:44 +08:00
} else if ( ! strcmp ( type , " socks4 " ) ) {
2011-11-06 21:12:50 +08:00
pd [ count ] . pt = SOCKS4_TYPE ;
2012-01-28 01:59:44 +08:00
} else if ( ! strcmp ( type , " socks5 " ) ) {
2011-11-06 21:12:50 +08:00
pd [ count ] . pt = SOCKS5_TYPE ;
2012-01-28 00:55:37 +08:00
} else
2014-07-21 19:17:24 +08:00
goto inv ;
2012-01-28 00:55:37 +08:00
2015-08-10 23:59:31 +08:00
if ( port_n )
2012-04-24 08:04:02 +08:00
count + + ;
2012-01-28 01:59:44 +08:00
} else {
if ( strstr ( buff , " [ProxyList] " ) ) {
list = 1 ;
2012-01-26 19:44:42 +08:00
} else if ( strstr ( buff , " random_chain " ) ) {
2012-01-28 01:59:44 +08:00
* ct = RANDOM_TYPE ;
2012-01-26 19:44:42 +08:00
} else if ( strstr ( buff , " strict_chain " ) ) {
2012-01-28 01:59:44 +08:00
* ct = STRICT_TYPE ;
2012-01-26 19:44:42 +08:00
} else if ( strstr ( buff , " dynamic_chain " ) ) {
2012-01-28 01:59:44 +08:00
* ct = DYNAMIC_TYPE ;
2013-06-23 13:13:40 +08:00
} else if ( strstr ( buff , " round_robin_chain " ) ) {
* ct = ROUND_ROBIN_TYPE ;
2012-01-28 01:59:44 +08:00
} else if ( strstr ( buff , " tcp_read_time_out " ) ) {
2012-01-26 19:44:42 +08:00
sscanf ( buff , " %s %d " , user , & tcp_read_time_out ) ;
2012-01-28 01:59:44 +08:00
} else if ( strstr ( buff , " tcp_connect_time_out " ) ) {
2012-01-26 19:44:42 +08:00
sscanf ( buff , " %s %d " , user , & tcp_connect_time_out ) ;
2012-01-28 01:59:44 +08:00
} else if ( strstr ( buff , " remote_dns_subnet " ) ) {
2016-12-09 12:42:55 +08:00
sscanf ( buff , " %s %u " , user , & remote_dns_subnet ) ;
2012-01-26 19:44:42 +08:00
if ( remote_dns_subnet > = 256 ) {
2012-01-28 01:59:44 +08:00
fprintf ( stderr ,
" remote_dns_subnet: invalid value. requires a number between 0 and 255. \n " ) ;
2012-01-26 19:44:42 +08:00
exit ( 1 ) ;
}
} else if ( strstr ( buff , " localnet " ) ) {
2012-01-28 01:59:44 +08:00
if ( sscanf ( buff , " %s %21[^/]/%15s " , user , local_in_addr_port , local_netmask ) < 3 ) {
2011-03-22 22:04:52 +08:00
fprintf ( stderr , " localnet format error " ) ;
exit ( 1 ) ;
}
/* clean previously used buffer */
2012-01-28 01:59:44 +08:00
memset ( local_in_port , 0 , sizeof ( local_in_port ) / sizeof ( local_in_port [ 0 ] ) ) ;
2011-03-22 22:04:52 +08:00
2012-01-28 01:59:44 +08:00
if ( sscanf ( local_in_addr_port , " %15[^:]:%5s " , local_in_addr , local_in_port ) < 2 ) {
2012-05-22 20:25:53 +08:00
PDEBUG ( " added localnet: netaddr=%s, netmask=%s \n " ,
2012-01-28 01:59:44 +08:00
local_in_addr , local_netmask ) ;
2011-03-22 22:04:52 +08:00
} else {
2012-01-28 01:59:44 +08:00
PDEBUG ( " added localnet: netaddr=%s, port=%s, netmask=%s \n " ,
local_in_addr , local_in_port , local_netmask ) ;
2011-03-22 22:04:52 +08:00
}
2012-01-28 01:59:44 +08:00
if ( num_localnet_addr < MAX_LOCALNET ) {
2011-02-25 23:16:58 +08:00
int error ;
2012-01-28 01:59:44 +08:00
error =
inet_pton ( AF_INET , local_in_addr ,
& localnet_addr [ num_localnet_addr ] . in_addr ) ;
if ( error < = 0 ) {
2011-02-25 23:16:58 +08:00
fprintf ( stderr , " localnet address error \n " ) ;
exit ( 1 ) ;
}
2012-01-28 01:59:44 +08:00
error =
inet_pton ( AF_INET , local_netmask ,
& localnet_addr [ num_localnet_addr ] . netmask ) ;
if ( error < = 0 ) {
2011-03-22 22:04:52 +08:00
fprintf ( stderr , " localnet netmask error \n " ) ;
2011-02-25 23:16:58 +08:00
exit ( 1 ) ;
}
2012-01-28 01:59:44 +08:00
if ( local_in_port [ 0 ] ) {
localnet_addr [ num_localnet_addr ] . port =
( short ) atoi ( local_in_port ) ;
2011-03-22 22:04:52 +08:00
} else {
localnet_addr [ num_localnet_addr ] . port = 0 ;
}
2011-02-25 23:16:58 +08:00
+ + num_localnet_addr ;
2012-01-28 01:59:44 +08:00
} else {
2011-02-25 23:16:58 +08:00
fprintf ( stderr , " # of localnet exceed %d. \n " , MAX_LOCALNET ) ;
}
2012-01-28 01:59:44 +08:00
} else if ( strstr ( buff , " chain_len " ) ) {
char * pc ;
int len ;
pc = strchr ( buff , ' = ' ) ;
2016-06-23 16:27:15 +08:00
if ( ! pc ) {
fprintf ( stderr , " error: missing equals sign '=' in chain_len directive. \n " ) ;
exit ( 1 ) ;
}
2012-01-28 01:59:44 +08:00
len = atoi ( + + pc ) ;
proxychains_max_chain = ( len ? len : 1 ) ;
} else if ( strstr ( buff , " quiet_mode " ) ) {
proxychains_quiet_mode = 1 ;
} else if ( strstr ( buff , " proxy_dns " ) ) {
proxychains_resolver = 1 ;
2020-05-06 05:33:42 +08:00
} else if ( strstr ( buff , " dnat " ) ) {
if ( sscanf ( buff , " %s %21[^ ] %21s \n " , user , dnat_orig_addr_port , dnat_new_addr_port ) < 3 ) {
fprintf ( stderr , " dnat format error " ) ;
exit ( 1 ) ;
}
/* clean previously used buffer */
memset ( dnat_orig_port , 0 , sizeof ( dnat_orig_port ) / sizeof ( dnat_orig_port [ 0 ] ) ) ;
memset ( dnat_new_port , 0 , sizeof ( dnat_new_port ) / sizeof ( dnat_new_port [ 0 ] ) ) ;
( void ) sscanf ( dnat_orig_addr_port , " %15[^:]:%5s " , dnat_orig_addr , dnat_orig_port ) ;
( void ) sscanf ( dnat_new_addr_port , " %15[^:]:%5s " , dnat_new_addr , dnat_new_port ) ;
if ( num_dnats < MAX_DNAT ) {
int error ;
error =
inet_pton ( AF_INET , dnat_orig_addr ,
& dnats [ num_dnats ] . orig_dst ) ;
if ( error < = 0 ) {
fprintf ( stderr , " dnat original destination address error \n " ) ;
exit ( 1 ) ;
}
error =
inet_pton ( AF_INET , dnat_new_addr ,
& dnats [ num_dnats ] . new_dst ) ;
if ( error < = 0 ) {
fprintf ( stderr , " dnat effective destination address error \n " ) ;
exit ( 1 ) ;
}
if ( dnat_orig_port [ 0 ] ) {
dnats [ num_dnats ] . orig_port =
( short ) atoi ( dnat_orig_port ) ;
} else {
dnats [ num_dnats ] . orig_port = 0 ;
}
if ( dnat_new_port [ 0 ] ) {
dnats [ num_dnats ] . new_port =
( short ) atoi ( dnat_new_port ) ;
} else {
dnats [ num_dnats ] . new_port = 0 ;
}
PDEBUG ( " added dnat: orig-dst=%s orig-port=%d new-dst=%s new-port=%d \n " , dnat_orig_addr , dnats [ num_dnats ] . orig_port , dnat_new_addr , dnats [ num_dnats ] . new_port ) ;
+ + num_dnats ;
} else {
fprintf ( stderr , " # of dnat exceed %d. \n " , MAX_DNAT ) ;
}
2011-02-25 17:40:11 +08:00
}
}
}
}
2016-02-04 20:49:43 +08:00
# ifndef BROKEN_FCLOSE
2011-02-25 17:40:11 +08:00
fclose ( file ) ;
2016-02-04 20:49:43 +08:00
# endif
2014-07-21 18:37:01 +08:00
if ( ! count ) {
fprintf ( stderr , " error: no valid proxy found in config \n " ) ;
exit ( 1 ) ;
}
2011-09-04 07:45:16 +08:00
* proxy_count = count ;
proxychains_got_chain_data = 1 ;
2018-12-02 21:46:55 +08:00
PDEBUG ( " proxy_dns: %s \n " , proxychains_resolver ? " ON " : " OFF " ) ;
2011-02-25 17:40:11 +08:00
}
2012-04-24 04:14:04 +08:00
/******* HOOK FUNCTIONS *******/
2011-02-25 17:40:11 +08:00
2013-01-21 08:54:45 +08:00
int close ( int fd ) {
2016-05-26 17:48:32 +08:00
if ( ! init_l ) {
2016-05-27 02:01:14 +08:00
if ( close_fds_cnt > = ( sizeof close_fds / sizeof close_fds [ 0 ] ) ) goto err ;
close_fds [ close_fds_cnt + + ] = fd ;
errno = 0 ;
return 0 ;
2016-05-26 17:48:32 +08:00
}
2020-09-21 00:03:54 +08:00
if ( ! proxychains_resolver ) return true_close ( fd ) ;
2013-01-21 08:54:45 +08:00
/* prevent rude programs (like ssh) from closing our pipes */
if ( fd ! = req_pipefd [ 0 ] & & fd ! = req_pipefd [ 1 ] & &
fd ! = resp_pipefd [ 0 ] & & fd ! = resp_pipefd [ 1 ] ) {
return true_close ( fd ) ;
}
2016-05-27 02:01:14 +08:00
err :
2014-01-08 13:38:59 +08:00
errno = EBADF ;
2013-01-21 08:54:45 +08:00
return - 1 ;
}
2015-09-16 04:16:20 +08:00
static int is_v4inv6 ( const struct in6_addr * a ) {
2018-01-09 21:30:02 +08:00
return ! memcmp ( a - > s6_addr , " \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \xff \xff " , 12 ) ;
2015-09-16 04:16:20 +08:00
}
2012-01-28 01:59:44 +08:00
int connect ( int sock , const struct sockaddr * addr , unsigned int len ) {
2015-06-14 18:16:59 +08:00
INIT ( ) ;
2012-11-07 23:49:14 +08:00
PFUNC ( ) ;
2015-06-14 18:16:59 +08:00
2012-01-28 01:59:44 +08:00
int socktype = 0 , flags = 0 , ret = 0 ;
2011-09-04 07:45:16 +08:00
socklen_t optlen = 0 ;
2011-11-06 21:12:50 +08:00
ip_type dest_ip ;
2015-06-14 17:53:33 +08:00
DEBUGDECL ( char str [ 256 ] ) ;
2011-02-25 23:16:58 +08:00
struct in_addr * p_addr_in ;
2015-08-10 23:59:31 +08:00
struct in6_addr * p_addr_in6 ;
2020-07-09 00:35:18 +08:00
dnat_arg * dnat = NULL ;
2011-03-22 22:04:52 +08:00
unsigned short port ;
2011-02-25 23:16:58 +08:00
size_t i ;
2012-03-03 14:24:05 +08:00
int remote_dns_connect = 0 ;
2012-01-28 01:59:44 +08:00
optlen = sizeof ( socktype ) ;
2015-08-10 23:59:31 +08:00
sa_family_t fam = SOCKFAMILY ( * addr ) ;
2012-01-28 01:59:44 +08:00
getsockopt ( sock , SOL_SOCKET , SO_TYPE , & socktype , & optlen ) ;
2015-08-10 23:59:31 +08:00
if ( ! ( ( fam = = AF_INET | | fam = = AF_INET6 ) & & socktype = = SOCK_STREAM ) )
2012-01-28 01:59:44 +08:00
return true_connect ( sock , addr , len ) ;
2011-02-25 23:16:58 +08:00
2015-08-10 23:59:31 +08:00
int v6 = dest_ip . is_v6 = fam = = AF_INET6 ;
2012-01-28 01:59:44 +08:00
p_addr_in = & ( ( struct sockaddr_in * ) addr ) - > sin_addr ;
2015-08-10 23:59:31 +08:00
p_addr_in6 = & ( ( struct sockaddr_in6 * ) addr ) - > sin6_addr ;
port = ! v6 ? ntohs ( ( ( struct sockaddr_in * ) addr ) - > sin_port )
: ntohs ( ( ( struct sockaddr_in6 * ) addr ) - > sin6_port ) ;
2015-09-16 04:16:20 +08:00
struct in_addr v4inv6 ;
if ( v6 & & is_v4inv6 ( p_addr_in6 ) ) {
2018-01-09 21:30:02 +08:00
memcpy ( & v4inv6 . s_addr , & p_addr_in6 - > s6_addr [ 12 ] , 4 ) ;
2015-09-16 04:16:20 +08:00
v6 = dest_ip . is_v6 = 0 ;
p_addr_in = & v4inv6 ;
}
2019-02-28 21:08:02 +08:00
if ( ! v6 & & ! memcmp ( p_addr_in , " \0 \0 \0 \0 " , 4 ) ) {
errno = ECONNREFUSED ;
return - 1 ;
}
2011-02-25 23:16:58 +08:00
2012-01-28 01:59:44 +08:00
// PDEBUG("localnet: %s; ", inet_ntop(AF_INET,&in_addr_localnet, str, sizeof(str)));
// PDEBUG("netmask: %s; " , inet_ntop(AF_INET, &in_addr_netmask, str, sizeof(str)));
2015-12-06 20:57:45 +08:00
PDEBUG ( " target: %s \n " , inet_ntop ( v6 ? AF_INET6 : AF_INET , v6 ? ( void * ) p_addr_in6 : ( void * ) p_addr_in , str , sizeof ( str ) ) ) ;
2011-09-04 07:45:16 +08:00
PDEBUG ( " port: %d \n " , port ) ;
2012-03-03 14:24:05 +08:00
// check if connect called from proxydns
2015-08-10 23:59:31 +08:00
remote_dns_connect = ! v6 & & ( ntohl ( p_addr_in - > s_addr ) > > 24 = = remote_dns_subnet ) ;
2012-03-03 14:24:05 +08:00
2020-07-09 00:35:18 +08:00
// more specific first
if ( ! v6 ) for ( i = 0 ; i < num_dnats & & ! remote_dns_connect & & ! dnat ; i + + )
if ( ( dnats [ i ] . orig_dst . s_addr = = p_addr_in - > s_addr ) )
if ( dnats [ i ] . orig_port & & ( dnats [ i ] . orig_port = = port ) )
dnat = & dnats [ i ] ;
if ( ! v6 ) for ( i = 0 ; i < num_dnats & & ! remote_dns_connect & & ! dnat ; i + + )
if ( dnats [ i ] . orig_dst . s_addr = = p_addr_in - > s_addr )
if ( ! dnats [ i ] . orig_port )
dnat = & dnats [ i ] ;
if ( dnat ) {
p_addr_in = & dnat - > new_dst ;
if ( dnat - > new_port )
port = dnat - > new_port ;
2020-05-06 05:33:42 +08:00
}
2015-08-10 23:59:31 +08:00
if ( ! v6 ) for ( i = 0 ; i < num_localnet_addr & & ! remote_dns_connect ; i + + ) {
2012-01-28 01:59:44 +08:00
if ( ( localnet_addr [ i ] . in_addr . s_addr & localnet_addr [ i ] . netmask . s_addr )
= = ( p_addr_in - > s_addr & localnet_addr [ i ] . netmask . s_addr ) ) {
2012-05-22 20:25:53 +08:00
if ( ! localnet_addr [ i ] . port | | localnet_addr [ i ] . port = = port ) {
2011-03-22 22:04:52 +08:00
PDEBUG ( " accessing localnet using true_connect \n " ) ;
2012-01-28 01:59:44 +08:00
return true_connect ( sock , addr , len ) ;
2011-03-22 22:04:52 +08:00
}
2011-02-25 23:16:58 +08:00
}
}
2011-11-06 21:12:50 +08:00
flags = fcntl ( sock , F_GETFL , 0 ) ;
2011-02-25 17:40:11 +08:00
if ( flags & O_NONBLOCK )
2012-01-28 01:59:44 +08:00
fcntl ( sock , F_SETFL , ! O_NONBLOCK ) ;
2012-01-28 00:55:37 +08:00
2015-08-10 23:59:31 +08:00
memcpy ( dest_ip . addr . v6 , v6 ? ( void * ) p_addr_in6 : ( void * ) p_addr_in , v6 ? 16 : 4 ) ;
2012-01-28 00:55:37 +08:00
2012-01-28 01:59:44 +08:00
ret = connect_proxy_chain ( sock ,
dest_ip ,
2015-08-10 23:59:31 +08:00
htons ( port ) ,
2012-01-28 01:59:44 +08:00
proxychains_pd , proxychains_proxy_count , proxychains_ct , proxychains_max_chain ) ;
2012-01-28 00:55:37 +08:00
2011-02-25 17:40:11 +08:00
fcntl ( sock , F_SETFL , flags ) ;
2011-11-06 21:12:50 +08:00
if ( ret ! = SUCCESS )
2012-01-28 01:59:44 +08:00
errno = ECONNREFUSED ;
2011-02-25 17:40:11 +08:00
return ret ;
}
2018-01-11 01:23:36 +08:00
# ifdef IS_SOLARIS
int __xnet_connect ( int sock , const struct sockaddr * addr , unsigned int len ) {
return connect ( sock , addr , len ) ;
}
# endif
2012-07-16 07:05:28 +08:00
static struct gethostbyname_data ghbndata ;
2012-01-28 01:59:44 +08:00
struct hostent * gethostbyname ( const char * name ) {
2012-04-24 04:14:04 +08:00
INIT ( ) ;
2012-01-28 01:59:44 +08:00
PDEBUG ( " gethostbyname: %s \n " , name ) ;
2012-01-28 00:55:37 +08:00
2011-02-25 17:40:11 +08:00
if ( proxychains_resolver )
2012-07-16 07:05:28 +08:00
return proxy_gethostbyname ( name , & ghbndata ) ;
2011-02-25 17:40:11 +08:00
else
return true_gethostbyname ( name ) ;
2012-01-28 00:55:37 +08:00
2011-02-25 17:40:11 +08:00
return NULL ;
}
2011-09-04 07:45:16 +08:00
2012-01-28 01:59:44 +08:00
int getaddrinfo ( const char * node , const char * service , const struct addrinfo * hints , struct addrinfo * * res ) {
2012-04-24 04:14:04 +08:00
INIT ( ) ;
2012-11-08 08:18:19 +08:00
PDEBUG ( " getaddrinfo: %s %s \n " , node ? node : " null " , service ? service : " null " ) ;
2012-01-28 00:55:37 +08:00
2011-02-25 17:40:11 +08:00
if ( proxychains_resolver )
2015-06-14 18:16:59 +08:00
return proxy_getaddrinfo ( node , service , hints , res ) ;
2011-02-25 17:40:11 +08:00
else
2015-06-14 18:16:59 +08:00
return true_getaddrinfo ( node , service , hints , res ) ;
2011-02-25 17:40:11 +08:00
}
2011-09-04 07:45:16 +08:00
2012-01-28 01:59:44 +08:00
void freeaddrinfo ( struct addrinfo * res ) {
2012-04-24 04:14:04 +08:00
INIT ( ) ;
2016-12-09 12:40:51 +08:00
PDEBUG ( " freeaddrinfo %p \n " , ( void * ) res ) ;
2012-01-28 00:55:37 +08:00
2011-02-25 17:40:11 +08:00
if ( ! proxychains_resolver )
true_freeaddrinfo ( res ) ;
2012-07-16 07:05:28 +08:00
else
proxy_freeaddrinfo ( res ) ;
2011-02-25 17:40:11 +08:00
}
2012-01-28 01:59:44 +08:00
2014-07-21 19:18:20 +08:00
int pc_getnameinfo ( const struct sockaddr * sa , socklen_t salen ,
char * host , socklen_t hostlen , char * serv ,
2012-12-18 05:17:00 +08:00
socklen_t servlen , int flags )
2011-02-25 17:40:11 +08:00
{
2012-04-24 04:14:04 +08:00
INIT ( ) ;
2012-12-18 05:17:00 +08:00
PFUNC ( ) ;
2012-01-28 00:55:37 +08:00
2011-02-25 17:40:11 +08:00
if ( ! proxychains_resolver ) {
2015-06-14 18:16:59 +08:00
return true_getnameinfo ( sa , salen , host , hostlen , serv , servlen , flags ) ;
2011-02-25 17:40:11 +08:00
} else {
2015-12-06 21:01:56 +08:00
if ( ! salen | | ! ( SOCKFAMILY ( * sa ) = = AF_INET | | SOCKFAMILY ( * sa ) = = AF_INET6 ) )
return EAI_FAMILY ;
int v6 = SOCKFAMILY ( * sa ) = = AF_INET6 ;
if ( salen < ( v6 ? sizeof ( struct sockaddr_in6 ) : sizeof ( struct sockaddr_in ) ) )
2012-12-18 06:21:58 +08:00
return EAI_FAMILY ;
2012-01-28 03:00:22 +08:00
if ( hostlen ) {
2015-12-06 21:01:56 +08:00
unsigned char v4inv6buf [ 4 ] ;
const void * ip = v6 ? ( void * ) & ( ( struct sockaddr_in6 * ) sa ) - > sin6_addr
: ( void * ) & ( ( struct sockaddr_in * ) sa ) - > sin_addr ;
unsigned scopeid = 0 ;
if ( v6 ) {
if ( is_v4inv6 ( & ( ( struct sockaddr_in6 * ) sa ) - > sin6_addr ) ) {
2018-01-09 21:30:02 +08:00
memcpy ( v4inv6buf , & ( ( struct sockaddr_in6 * ) sa ) - > sin6_addr . s6_addr [ 12 ] , 4 ) ;
2015-12-06 21:01:56 +08:00
ip = v4inv6buf ;
v6 = 0 ;
} else
scopeid = ( ( struct sockaddr_in6 * ) sa ) - > sin6_scope_id ;
}
if ( ! inet_ntop ( v6 ? AF_INET6 : AF_INET , ip , host , hostlen ) )
2012-12-18 05:41:51 +08:00
return EAI_OVERFLOW ;
2015-12-06 21:01:56 +08:00
if ( scopeid ) {
size_t l = strlen ( host ) ;
if ( snprintf ( host + l , hostlen - l , " %%%u " , scopeid ) > = hostlen - l )
return EAI_OVERFLOW ;
}
2012-12-18 05:41:51 +08:00
}
if ( servlen ) {
if ( snprintf ( serv , servlen , " %d " , ntohs ( SOCKPORT ( * sa ) ) ) > = servlen )
return EAI_OVERFLOW ;
2012-01-28 03:00:22 +08:00
}
2011-02-25 17:40:11 +08:00
}
2015-06-14 18:16:59 +08:00
return 0 ;
2011-02-25 17:40:11 +08:00
}
2011-02-25 23:16:58 +08:00
2012-01-28 01:59:44 +08:00
struct hostent * gethostbyaddr ( const void * addr , socklen_t len , int type ) {
2015-06-14 18:16:59 +08:00
INIT ( ) ;
PDEBUG ( " TODO: proper gethostbyaddr hook \n " ) ;
2011-09-04 07:45:16 +08:00
static char buf [ 16 ] ;
static char ipv4 [ 4 ] ;
2012-01-28 01:59:44 +08:00
static char * list [ 2 ] ;
2012-11-04 11:58:48 +08:00
static char * aliases [ 1 ] ;
2011-09-04 07:45:16 +08:00
static struct hostent he ;
2012-01-28 00:55:37 +08:00
2011-02-25 17:40:11 +08:00
if ( ! proxychains_resolver )
2012-01-28 01:59:44 +08:00
return true_gethostbyaddr ( addr , len , type ) ;
2011-09-04 07:45:16 +08:00
else {
2012-01-28 00:55:37 +08:00
2011-09-04 08:03:47 +08:00
PDEBUG ( " len %u \n " , len ) ;
2012-01-28 01:59:44 +08:00
if ( len ! = 4 )
return NULL ;
2011-09-04 07:45:16 +08:00
he . h_name = buf ;
memcpy ( ipv4 , addr , 4 ) ;
list [ 0 ] = ipv4 ;
list [ 1 ] = NULL ;
he . h_addr_list = list ;
he . h_addrtype = AF_INET ;
2012-11-04 11:58:48 +08:00
aliases [ 0 ] = NULL ;
he . h_aliases = aliases ;
2011-09-04 07:45:16 +08:00
he . h_length = 4 ;
2012-01-28 01:59:44 +08:00
pc_stringfromipv4 ( ( unsigned char * ) addr , buf ) ;
2011-09-04 07:45:16 +08:00
return & he ;
}
2011-02-25 17:40:11 +08:00
return NULL ;
}
2015-01-24 00:14:28 +08:00
2015-02-17 22:27:01 +08:00
# ifndef MSG_FASTOPEN
# define MSG_FASTOPEN 0x20000000
# endif
2015-01-24 00:14:28 +08:00
ssize_t sendto ( int sockfd , const void * buf , size_t len , int flags ,
const struct sockaddr * dest_addr , socklen_t addrlen ) {
2015-06-14 18:16:59 +08:00
INIT ( ) ;
PFUNC ( ) ;
2015-01-24 00:14:28 +08:00
if ( flags & MSG_FASTOPEN ) {
if ( ! connect ( sockfd , dest_addr , addrlen ) & & errno ! = EINPROGRESS ) {
return - 1 ;
}
dest_addr = NULL ;
addrlen = 0 ;
flags & = ~ MSG_FASTOPEN ;
}
return true_sendto ( sockfd , buf , len , flags , dest_addr , addrlen ) ;
}