/***************************************************************************** * MOCKS, a RFC1928 compliant SOCKSv5 server * Copyright (C) 2004 Dan Horobeanu * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include "error.h" #include "misc.h" #include "child.h" #include "socksd.h" #include "up_proxy.h" int socks_port = 1080; char sz_logfile[256] = PROG_NAME".log"; char sz_pidfile[256] = PROG_NAME".pid"; int buf_size = 64*1024; int backlog = 5; int neg_timeo = 5; int con_idle_timeo = 300; int bind_timeo = 30; int shutd_timeo = 3; int max_con_cnt = 50; struct t_proxy *up_proxy = NULL; int filter_policy = FP_ALLOW; int filter_except_cnt = 0; uint32_t filter_excepts[MAX_FILTER_EXCEPTS]; int filter_except_masks[MAX_FILTER_EXCEPTS]; char sz_cfgfile[256] = PROG_NAME".conf"; int con_cnt = 0; int child = 0; int sk_socks; struct sockaddr ad_socks; /******************* * main() function *******************/ int main( int argc, char **argv ) { int force_load = FALSE; int sksize; char s[256]; struct sigaction sa; int res; int i; int act=-1; FILE *f; int allow; uint32_t adam; /* ** Parse command line parameters */ for( i=1; isin_port) ); logstr(s,NULL); if( up_proxy ) { strcpy(s,"Relaying all traffic through "); sprintf( s+strlen(s),"%u.%u.%u.%u:%u", up_proxy->ip & 0xFF, (up_proxy->ip >> 8) & 0xFF, (up_proxy->ip >> 16) & 0xFF, up_proxy->ip >> 24, up_proxy->port ); logstr(s,NULL); } /* ** Now, remember we must act as a daemon, ** so let's fork() and detach. */ switch( fork() ) { case 0: setsid(); break; case -1: printf("ERROR\n\tfork() failed - cannot detach daemon\n"); exit(1); default: exit(0); } /* ** Create PID file */ f = fopen(sz_pidfile,"w"); if( !f ) logstr("WARNING: PID file could not be created!\n",NULL); else { fprintf(f,"%u",getpid()); fclose(f); } /* ** Entering the accept loop */ while( 1 ) { /* ** If we're already working with the maximum number of ** client connections, wake up every second to check ** if any connection closed and if not, ignore any other ** connection requests. */ if( con_cnt >= max_con_cnt ) { sleep(1); continue; } sksize = SOCK_SIZE; sk_client = accept( sk_socks,&ad_client,&sksize ); if( sk_client==-1 ) { if( errno!=EINTR ) logstr("Error: accept() failed",NULL); continue; } /* * Match the connection against our * client filter. */ allow = (filter_policy == FP_ALLOW); for( i=0; i= max_con_cnt ) { printf("Maximum daemon load reached: %d active connections", con_cnt); logstr(s,NULL); } close(sk_client); break; } /* end switch */ } /* end while */ close(sk_socks); return 0; } /***************************************************************** * handle_sig() : signal handler for SIGCHLD, SIGTERM and SIGALRM *****************************************************************/ void handle_sig( int sig ) { char s[256]; switch( sig ) { case SIGTERM: if( !child ) { unlink(sz_pidfile); sprintf( s, PROG_NAME" "PROG_VERSION" shutting down cleanly " ": killing %d connections",con_cnt ); logstr(s,NULL); } exit(0); break; case SIGCHLD: while( waitpid(-1,NULL,WNOHANG) > 0 ) con_cnt--; break; case SIGALRM: if( child ) { sprintf(s,"Connection closed (%s)",sz_error[ERR_NEGTIME]); logstr(s,&ad_client); exit(ERR_NEGTIME); } exit(0); break; } } /********************************************** * print_help() : output a short help message **********************************************/ void print_help( char *exe_path ) { printf("\n"); print_ver(); printf("USAGE:\n\t%s [OPTIONS] ACTION\n",exe_path); printf("OPTIONS\n"); printf("\t-h, --help display this help screen and exit\n"); printf("\t-v, --version display program version and exit\n"); printf("\t-c file, --config file use configuration file 'file'\n"); printf("\t-f, --forceload force loading SOCKS daemon even if\n"); printf("\t PID file exists\n"); printf("ACTIONS\n"); printf("\tstart start SOCKS daemon\n"); printf("\tshutdown shutdown SOCKS daemon\n"); printf("\n"); } /****************************************** * print_ver() : output program version ******************************************/ void print_ver() { printf(PROG_NAME" version "PROG_VERSION" ("PROG_DATE")\n"); } /****************************************************** * load_config() : load daemon configuration from file ******************************************************/ int load_config() { FILE *f; char buf[256]; char var[32]=""; char val[256]=""; int i; int err; struct hostent *he; char *p; int proxy_type = 0; char proxy_name[256]=""; int proxy_port; char proxy_usr[256]=""; char proxy_pwd[256]=""; char var_name[CFG_VARS_CNT][32] = { "PORT", "LOG_FILE", "PID_FILE", "BUFFER_SIZE", "BACKLOG", "NEGOTIATION_TIMEOUT", "CONNECTION_IDLE_TIMEOUT", "BIND_TIMEOUT", "SHUTDOWN_TIMEOUT", "MAX_CONNECTIONS", "FILTER_POLICY", "FILTER_EXCEPTION", "UP_PROXY_TYPE", "UP_PROXY_ADDR","UP_PROXY_PORT", "UP_PROXY_USER", "UP_PROXY_PASSWD", "MOCKS_ADDR" }; void *var_ptr[CFG_VARS_CNT] = { &socks_port, sz_logfile, sz_pidfile, &buf_size, &backlog, &neg_timeo, &con_idle_timeo, &bind_timeo, &shutd_timeo, &max_con_cnt, NULL, NULL, NULL, proxy_name, &proxy_port, proxy_usr, proxy_pwd, ad_socks.sa_data+2 }; char var_type[CFG_VARS_CNT] = { 'n','s','s', 'n','n','n', 'n','n','n', 'n','s','s', 's','s','n', 's','s','a' }; //up_proxy = proxy_new(PROXY_SOCKS5,0x0101A8C0,1080,0,NULL,NULL); if( (f=fopen(sz_cfgfile,"r"))==NULL ) return ERR_READ; do { if( !fgets(buf,256,f) ) break; for( i=0; buf[i] && buf[i]!='#'; i++ ) ; buf[i] = 0; sscanf(buf,"%32s = %s",var,val); if( (var[0] && !val[0]) || (!var[0] && val[0]) ) return ERR_READ; if( !var[0] && !val[0] ) continue; if( !strcmp(var,"FILTER_POLICY") ) { if( !strcmp(val,"DENY") ) filter_policy = FP_DENY; } else if( !strcmp(var,"FILTER_EXCEPTION") ) { p = strstr(val,"/"); if( p ) { sscanf(p+1,"%u",filter_except_masks+filter_except_cnt); if( filter_except_masks[filter_except_cnt] > 32 ) return ERR_READ; *p = 0; } else filter_except_masks[filter_except_cnt] = 32; he = gethostbyname(val); if( !he ) return ERR_READ; memcpy(filter_excepts+filter_except_cnt,he->h_addr_list[0],4); filter_except_cnt++; } else if( !strcmp(var,"UP_PROXY_TYPE") ) { if( !strcmp(val,"SOCKS5") ) proxy_type = PROXY_SOCKS5; else if( !strcmp(val,"SOCKS4") ) proxy_type = PROXY_SOCKS4; else if( !strcmp(val,"HTTPCONNECT") ) proxy_type = PROXY_HTTPCONNECT; else return ERR_READ; } else { err = 1; for( i=0; ih_addr_list[0],4); break; } err = 0; } if( err ) return ERR_READ; } } while( 1 ); if( proxy_type ) { if( proxy_usr[0] ) up_proxy = proxy_new( proxy_type, proxy_name, proxy_port, PROXY_FL_AUTH, proxy_usr, proxy_pwd ); else up_proxy = proxy_new(proxy_type,proxy_name,proxy_port,0,NULL,NULL); } fclose(f); return ERR_NONE; }