/*************************************************************************** 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. * * * ***************************************************************************/ #define _GNU_SOURCE #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "core.h" #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) #define MAX_CHAIN 30*1024 int tcp_read_time_out; int tcp_connect_time_out; chain_type proxychains_ct; proxy_data proxychains_pd[MAX_CHAIN]; int proxychains_proxy_count = 0; int proxychains_got_chain_data = 0; int proxychains_max_chain = 1; int proxychains_quiet_mode = 0; int proxychains_resolver = 0; static int init_l = 0; static inline void get_chain_data( proxy_data *pd, unsigned int *proxy_count, chain_type *ct); static void init_lib() { // proxychains_write_log("ProxyChains-"VERSION // " (http://proxychains.sf.net)\n"); get_chain_data(proxychains_pd,&proxychains_proxy_count,&proxychains_ct); true_connect = (connect_t) dlsym(RTLD_NEXT, "connect"); if (!true_connect) { fprintf(stderr, "Cannot load symbol 'connect' %s\n", dlerror()); exit(1); } else { // PDEBUG( "loaded symbol 'connect'" // " real addr %p wrapped addr %p\n", // true_connect, connect); } true_gethostbyname = (gethostbyname_t) dlsym(RTLD_NEXT, "gethostbyname"); if (!true_gethostbyname) { fprintf(stderr, "Cannot load symbol 'gethostbyname' %s\n", dlerror()); exit(1); } else { // PDEBUG( "loaded symbol 'gethostbyname'" // " real addr %p wrapped addr %p\n", // true_gethostbyname, gethostbyname); } true_getaddrinfo = (getaddrinfo_t) dlsym(RTLD_NEXT, "getaddrinfo"); if (!true_getaddrinfo) { fprintf(stderr, "Cannot load symbol 'getaddrinfo' %s\n", dlerror()); exit(1); } else { // PDEBUG( "loaded symbol 'getaddrinfo'" // " real addr %p wrapped addr %p\n", // true_getaddrinfo, getaddrinfo); } true_freeaddrinfo = (freeaddrinfo_t) dlsym(RTLD_NEXT, "freeaddrinfo"); if (!true_freeaddrinfo) { fprintf(stderr, "Cannot load symbol 'freeaddrinfo' %s\n", dlerror()); exit(1); } else { // PDEBUG( "loaded symbol 'freeaddrinfo'" // " real addr %p wrapped addr %p\n", // true_freeaddrinfo, freeaddrinfo); } true_gethostbyaddr = (gethostbyaddr_t) dlsym(RTLD_NEXT, "gethostbyaddr"); if (!true_gethostbyaddr) { fprintf(stderr, "Cannot load symbol 'gethostbyaddr' %s\n", dlerror()); exit(1); } else { // PDEBUG( "loaded symbol 'gethostbyaddr'" // " real addr %p wrapped addr %p\n", // true_gethostbyaddr, gethostbyaddr); } true_getnameinfo = (getnameinfo_t) dlsym(RTLD_NEXT, "getnameinfo"); if (!true_getnameinfo) { fprintf(stderr, "Cannot load symbol 'getnameinfo' %s\n", dlerror()); exit(1); } else { // PDEBUG( "loaded symbol 'getnameinfo'" // " real addr %p wrapped addr %p\n", // true_getnameinfo, getnameinfo); } init_l = 1; } /* * XXX. Same thing is defined in proxychains main.c it * needs to be changed, too. */ #define PROXYCHAINS_CONF_FILE "PROXYCHAINS_CONF_FILE" static inline void get_chain_data( proxy_data *pd, unsigned int *proxy_count, chain_type *ct) { int count=0,port_n=0,list=0; char buff[1024],type[1024],host[1024],user[1024]; char *env; FILE* file; if(proxychains_got_chain_data) return; //Some defaults tcp_read_time_out=4*1000; tcp_connect_time_out=10*1000; *ct=DYNAMIC_TYPE; env = NULL; /* * Get path to configuration file from env this file has priority * if it's defined. */ env = getenv(PROXYCHAINS_CONF_FILE); snprintf(buff,256,"%s/.proxychains/proxychains.conf",getenv("HOME")); if(!(file=fopen(env,"r"))) if(!(file=fopen("./proxychains.conf","r"))) if(!(file=fopen(buff,"r"))) if(!(file=fopen("/etc/proxychains.conf","r"))) { perror("Can't locate proxychains.conf"); exit(1); } while(fgets(buff,sizeof(buff),file)) { if(buff[strspn(buff," ")]!='#') { if(list) { bzero(&pd[count], sizeof(proxy_data)); pd[count].ps=PLAY_STATE; port_n=0; sscanf(buff,"%s %s %d %s %s", type,host,&port_n, pd[count].user,pd[count].pass); pd[count].ip=inet_addr(host); pd[count].port=htons((unsigned short)port_n); if(!strcmp(type,"http")) { pd[count].pt=HTTP_TYPE; }else if(!strcmp(type,"socks4")) { pd[count].pt=SOCKS4_TYPE; }else if(!strcmp(type,"socks5")) { pd[count].pt=SOCKS5_TYPE; }else continue; if( pd[count].ip && pd[count].ip!=-1 && port_n) if(++count==MAX_CHAIN) break; } else { if(strstr(buff,"[ProxyList]")) { list=1; } else if(strstr(buff,"random_chain")) { *ct=RANDOM_TYPE; } else if(strstr(buff,"strict_chain")) { *ct=STRICT_TYPE; } else if(strstr(buff,"dynamic_chain")) { *ct=DYNAMIC_TYPE; }else if(strstr(buff,"tcp_read_time_out")){ sscanf(buff,"%s %d",user,&tcp_read_time_out) ; }else if(strstr(buff,"tcp_connect_time_out")){ sscanf(buff,"%s %d",user,&tcp_connect_time_out) ; }else if(strstr(buff,"chain_len")){ char *pc;int len; pc=strchr(buff,'='); 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; } } } } fclose(file); *proxy_count=count; proxychains_got_chain_data=1; } int connect (int sock, const struct sockaddr *addr, unsigned int len) { int socktype=0,optlen=0,flags=0,ret=0; if(!init_l) init_lib(); optlen=sizeof(socktype); getsockopt(sock,SOL_SOCKET,SO_TYPE,&socktype,&optlen); if (! (SOCKFAMILY(*addr)==AF_INET && socktype==SOCK_STREAM)) return true_connect(sock,addr,len); flags=fcntl(sock, F_GETFL, 0); if(flags & O_NONBLOCK) fcntl(sock, F_SETFL, !O_NONBLOCK); ret=connect_proxy_chain( sock, SOCKADDR(*addr), SOCKPORT(*addr), proxychains_pd, proxychains_proxy_count, proxychains_ct, proxychains_max_chain ); fcntl(sock, F_SETFL, flags); if(ret!=SUCCESS) errno=ECONNREFUSED; return ret; } struct hostent *gethostbyname(const char *name) { PDEBUG("gethostbyname: %s\n",name); if(!init_l) init_lib(); if(proxychains_resolver) return proxy_gethostbyname(name); else return true_gethostbyname(name); return NULL; } int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) { int ret = 0; PDEBUG("getaddrinfo: %s %s\n",node ,service); if(!init_l) init_lib(); if(proxychains_resolver) ret = proxy_getaddrinfo(node, service, hints, res); else ret = true_getaddrinfo(node, service, hints, res); return ret; } void freeaddrinfo(struct addrinfo *res) { PDEBUG("freeaddrinfo %p \n",res); if(!init_l) init_lib(); if(!proxychains_resolver) true_freeaddrinfo(res); else { free(res->ai_addr); free(res); } return; } int getnameinfo (const struct sockaddr * sa, socklen_t salen, char * host, socklen_t hostlen, char * serv, socklen_t servlen, unsigned int flags) { int ret = 0; if(!init_l) init_lib(); if(!proxychains_resolver) { ret = true_getnameinfo(sa,salen,host,hostlen, serv,servlen,flags); } else { if(hostlen) strncpy(host, inet_ntoa(SOCKADDR_2(*sa)),hostlen); if(servlen) snprintf(serv, servlen,"%d",ntohs(SOCKPORT(*sa))); } PDEBUG("getnameinfo: %s %s\n", host, serv); return ret; } struct hostent *gethostbyaddr (const void *addr, socklen_t len, int type) { PDEBUG("TODO: gethostbyaddr hook\n"); if(!init_l) init_lib(); if(!proxychains_resolver) return true_gethostbyaddr(addr,len,type); return NULL; }