├── AUTHORS ├── CMakeLists.txt ├── COPYING ├── README.md ├── appveyor.yml ├── config.h ├── src ├── auth-util.c ├── auth-util.h ├── configd-util.c ├── configd-util.h ├── libsocks │ ├── bor-util.c │ ├── bor-util.h │ ├── client.c │ ├── client.h │ ├── log-util.c │ ├── log-util.h │ ├── net-util.c │ ├── net-util.h │ ├── output-util.c │ ├── output-util.h │ ├── socks-common.c │ ├── socks-common.h │ ├── socks4.c │ ├── socks4.h │ ├── socks5-client.c │ ├── socks5-client.h │ ├── socks5-server.c │ ├── socks5-server.h │ ├── ssl-util.c │ ├── ssl-util.h │ └── unisocket.h ├── nsocks.c ├── rcsocks.c ├── rssocks.c ├── ssocks.c ├── ssocksd.auth ├── ssocksd.c ├── ssocksd.conf ├── win_getopt.c └── win_getopt.h └── test.sh /AUTHORS: -------------------------------------------------------------------------------- 1 | Hugo Caron 2 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(ssocks) 3 | 4 | include_directories(. src) 5 | AUX_SOURCE_DIRECTORY(src/libsocks AUX) 6 | list(APPEND AUX src/configd-util.c src/auth-util.c) 7 | 8 | if (WIN32) 9 | list(APPEND AUX src/win_getopt.c) 10 | link_libraries(ws2_32) 11 | endif(WIN32) 12 | 13 | add_executable(ssocks src/ssocks.c ${AUX}) 14 | add_executable(ssocksd src/ssocksd.c ${AUX}) 15 | add_executable(nsocks src/nsocks.c ${AUX}) 16 | add_executable(rcsocks src/rcsocks.c ${AUX}) 17 | add_executable(rssocks src/rssocks.c ${AUX}) 18 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) 2011 by Hugo Caron 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## README 2 | 3 | sSocks是一个跨平台的socks代理工具套装,可用来开启socks代理服务,支持socks5验证,支持IPV6和UDP,并提供反向socks代理服务 4 | 5 | **nsocks** 类似通过Socks5代理后的netcat,可用来测试socks server 6 | 7 | **ssocksd** 用来开启Socks5代理服务 8 | 9 | **ssocks** 本地启用Socks5服务,并反弹到另一IP地址 10 | 11 | **rcsocks** 接收反弹过来的Socks5服务,并转向另一端口 12 | 13 | 原项目地址: 14 | 15 | - [sSocks](https://github.com/tostercx/ssocks) 16 | 17 | - [sSocks](https://sourceforge.net/projects/ssocks/) 18 | 19 | ## How to use? 20 | 21 | Windows Visual Studio 2019 编译 22 | 23 | ```console 24 | mkdir build 25 | cd build 26 | cmake .. 27 | msbuild ssocks.sln /p:Configuration=Release 28 | ``` 29 | 30 | Linux 编译 31 | ```console 32 | mkdir build 33 | cd build 34 | cmake .. 35 | make 36 | ``` 37 | 38 | ## Original README 39 | 40 | Features: 41 | - Configuration file 42 | - Authentication file 43 | - Generate a connection log file 44 | - Daemon mode 45 | - Server support bind mode 46 | - Socks4 support (if authentication is enable socks4 is disable) 47 | - Support choose of interface to bind 48 | 49 | ------------------------------------------------------------------------ 50 | TODO: 51 | - IPV6 support 52 | - UDP support 53 | - Stock password with a hash ( md5 or sha256 ) 54 | - GSSAPI auth support ( maybe ) 55 | - Set number of client max ( actually 255 is in client.h MAXCLI var ) 56 | - Add --pid-file option to server 57 | - ssocks bind localhost, not all 58 | - SSL implements out of RFC 59 | 60 | ------------------------------------------------------------------------ 61 | Software: 62 | - nsocks is a netcat like through a socks5 (usefull to test socks server) 63 | - ssocksd is the socks5 server 64 | - ssocks is a socks5 relay, it run a socks server on your localhost interface, 65 | and relay all data to the server specified in parameter (works but under dev) 66 | - rssocks is a reverse socks5 server ( POC under dev ) 67 | - rcsocks is a reverse socks5 client ( POC under dev ) 68 | 69 | File: 70 | - /etc/ssocksd.conf is server configuration file 71 | - /etc/ssocksd.auth is password file 72 | - /var/log/ssocksd.log is default log (specified in configuration file) 73 | - /var/run/ssocksd.pid is create in daemon mode and delete 74 | when it receive SIGTERM 75 | 76 | ------------------------------------------------------------------------ 77 | Copyright (C) 2011 by Hugo Caron 78 | 79 | Permission is hereby granted, free of charge, to any person obtaining a copy 80 | of this software and associated documentation files (the "Software"), to deal 81 | in the Software without restriction, including without limitation the rights 82 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 83 | copies of the Software, and to permit persons to whom the Software is 84 | furnished to do so, subject to the following conditions: 85 | 86 | The above copyright notice and this permission notice shall be included in 87 | all copies or substantial portions of the Software. 88 | 89 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 90 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 91 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 92 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 93 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 94 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 95 | THE SOFTWARE. 96 | 97 | ------------------------------------------------------------------------ -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 0.0.14.{build} 2 | shallow_clone: true 3 | image: Visual Studio 2019 4 | 5 | build_script: 6 | - cmd: call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" 7 | 8 | - mkdir build 9 | - cd build 10 | - cmake .. 11 | - msbuild ssocks.sln /p:Configuration=Release 12 | - cd .. 13 | 14 | - SET zip=ssocks-win32-%APPVEYOR_BUILD_VERSION%.zip 15 | - 7z a %zip% build/Release/*.exe src/*.conf src/*.auth 16 | - appveyor PushArtifact %zip% 17 | 18 | test_script: 19 | - cd build/Release 20 | - git clone https://github.com/tostercx/nc111nt-bin 21 | 22 | - ps: "$tstr = ([char[]]([char]'a'..[char]'z') | sort {get-random})[0..5] -join ''" 23 | - ps: '"HTTP/1.0 200 OK`r`nContent-Length: 6`r`n`r`n$tstr" | Out-File -Encoding ASCII test.data' 24 | - ps: Start-Process .\nc111nt-bin\nc.exe '-l -p 8080' -RedirectStandardInput .\test.data 25 | 26 | - ps: Start-Process .\ssocksd.exe '-p 8081' 27 | - ps: $ret=$(curl.exe -sSx socks5://127.0.0.1:8081 127.0.0.1:8080) 28 | - ps: if($tstr -ne $ret) { echo "Expected $tstr, got $ret"; exit 1 } 29 | 30 | - cd ../.. 31 | -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | #ifndef SSOCKS_CONFIG 2 | #define SSOCKS_CONFIG 3 | 4 | #define PACKAGE_NAME "ssocks" 5 | #define PACKAGE_TARNAME "ssocks" 6 | #define PACKAGE_VERSION "0.0.14" 7 | #define PACKAGE_STRING "ssocks 0.0.14" 8 | #define PACKAGE_BUGREPORT "https://github.com/tostercx/ssocks/issues" 9 | #define PACKAGE_URL "" 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /src/auth-util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * auth-util.c 3 | * 4 | * Created on: 2011-04-02 5 | * Author: Hugo Caron 6 | * Email: 7 | * 8 | * 9 | * 10 | * Copyright (C) 2011 by Hugo Caron 11 | * 12 | * Permission is hereby granted, free of charge, to any person obtaining a copy 13 | * of this software and associated documentation files (the "Software"), to deal 14 | * in the Software without restriction, including without limitation the rights 15 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | * copies of the Software, and to permit persons to whom the Software is 17 | * furnished to do so, subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be included in 20 | * all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 | * THE SOFTWARE. 29 | */ 30 | 31 | #define MAX_AUTH_LOGIN 128 32 | #define MAX_AUTH_UNAME 255 33 | 34 | #include 35 | 36 | #include 37 | #include 38 | #include 39 | 40 | typedef struct { 41 | char uname[MAX_AUTH_UNAME]; 42 | char passwd[MAX_AUTH_UNAME]; 43 | } Cred; 44 | 45 | Cred tcred[MAX_AUTH_LOGIN]; 46 | int ncred = 0; 47 | 48 | int load_auth_file(char *filename) { 49 | int k; 50 | char *line = NULL; 51 | char buf[(MAX_AUTH_UNAME*2)+1]; 52 | 53 | TRACE(L_DEBUG, "auth: open file %s ...", filename); 54 | FILE *fp = fopen(filename, "r"); 55 | 56 | if ( fp == 0 ) { 57 | ERROR(L_NOTICE, "auth: can't open file %s", filename); 58 | return -1; 59 | } 60 | 61 | while(ncred < MAX_AUTH_LOGIN && !feof(fp) ) { 62 | if(fgets(buf, sizeof(buf), fp) == NULL) 63 | break; 64 | 65 | /* Warn: Potential overflow */ 66 | k = sscanf(buf, "%254[^#:]:%254s", tcred[ncred].uname, tcred[ncred].passwd); 67 | 68 | if ( k != 2 ) { 69 | continue; 70 | } 71 | /* Avoid whitespace maybe fscanf can do this */ 72 | trim(tcred[ncred].uname); 73 | trim(tcred[ncred].passwd); 74 | TRACE(L_DEBUG, "auth: load user %s:%s", 75 | tcred[ncred].uname, tcred[ncred].passwd); 76 | 77 | ncred++; 78 | } 79 | 80 | TRACE(L_DEBUG, "auth: close file"); 81 | fclose(fp); 82 | free(line); 83 | return ncred; 84 | } 85 | 86 | int check_auth(char *uname, char *passwd) { 87 | int i; 88 | for (i=0; i < ncred; ++i) 89 | if ( strcmp(uname, tcred[i].uname) == 0 90 | && strcmp(passwd, tcred[i].passwd) == 0) 91 | return 1; 92 | 93 | return -1; 94 | } 95 | -------------------------------------------------------------------------------- /src/auth-util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * auth-util.h 3 | * 4 | * Created on: 2011-04-02 5 | * Author: Hugo Caron 6 | * Email: 7 | * 8 | * Desc: Content function to load users credentials from a file 9 | * 10 | * 11 | * Copyright (C) 2011 by Hugo Caron 12 | * 13 | * Permission is hereby granted, free of charge, to any person obtaining a copy 14 | * of this software and associated documentation files (the "Software"), to deal 15 | * in the Software without restriction, including without limitation the rights 16 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | * copies of the Software, and to permit persons to whom the Software is 18 | * furnished to do so, subject to the following conditions: 19 | * 20 | * The above copyright notice and this permission notice shall be included in 21 | * all copies or substantial portions of the Software. 22 | * 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 | * THE SOFTWARE. 30 | */ 31 | #ifndef AUTH_UTILS__H 32 | #define AUTH_UTILS__H 33 | 34 | int load_auth_file(char *filename); 35 | int check_auth(char *uname, char *passwd); 36 | 37 | 38 | #endif /* AUTH_UTILS__H */ 39 | -------------------------------------------------------------------------------- /src/configd-util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * configd-util.c 3 | * 4 | * Created on: 2011-04-03 5 | * Author: Hugo Caron 6 | * Email: 7 | * 8 | * Copyright (C) 2011 by Hugo Caron 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | 29 | #include "configd-util.h" 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | #ifdef _WIN32 37 | #define strcasecmp _stricmp 38 | #else 39 | #include 40 | /* Daemon function */ 41 | #include 42 | #endif 43 | 44 | 45 | int loadConfigFile(char *filename, struct globalArgsServer_t *c) { 46 | int k; 47 | char var[255]; 48 | char val[255]; 49 | char buf[510]; 50 | 51 | TRACE(L_DEBUG, "config: open file %s ...", filename); 52 | 53 | 54 | FILE *fp = fopen(filename, "r"); 55 | if ( fp == 0 ) { 56 | ERROR(L_NOTICE, "config: can't open file %s", filename); 57 | return -1; 58 | } 59 | 60 | while(!feof(fp)) { 61 | if(fgets(buf, sizeof(buf), fp) == NULL) 62 | break; 63 | 64 | k = sscanf(buf, "%254[^#=]=%254[^\n]\n", var, val); 65 | 66 | if ( k != 2 ) { 67 | continue; 68 | } 69 | trim(var); 70 | trim(val); 71 | if(strcasecmp(var, "PORT") == 0 ) { 72 | c->port = atoi(val); 73 | } else if(strcasecmp(var, "AUTH") == 0 ) { 74 | strncpy_sx(c->fileauth, val, 75 | sizeof(globalArgsServer.fileauth)); 76 | } else if(strcasecmp(var, "LOG") == 0 ) { 77 | strncpy_sx(c->filelog, val, 78 | sizeof(globalArgsServer.filelog)); 79 | } else if(strcasecmp(var, "DAEMON") == 0 ) { 80 | c->daemon = atoi(val); 81 | } else if(strcasecmp(var, "BIND") == 0 ) { 82 | strncpy_sx(c->bindAddr, val, 83 | sizeof(globalArgsServer.bindAddr)); 84 | } else if(strcasecmp(var, "VERBOSITY") == 0 ) { 85 | c->verbosity = atoi(val); 86 | } else if(strcasecmp(var, "GUEST") == 0 ) { 87 | c->guest = atoi(val); 88 | #ifdef HAVE_LIBSSL 89 | } else if(strcasecmp(var, "CERT") == 0 ) { 90 | strncpy_sx(c->filecert, val, 91 | sizeof(globalArgsServer.filecert)); 92 | } else if(strcasecmp(var, "KEY") == 0 ) { 93 | strncpy_sx(c->filekey, val, 94 | sizeof(globalArgsServer.filekey)); 95 | } else if(strcasecmp(var, "SSL") == 0 ) { 96 | c->ssl = atoi(val); 97 | #endif /* HAVE_LIBSSL */ 98 | } else { 99 | ERROR(L_NOTICE, "config: unknown option %s", var); 100 | return -1; 101 | } 102 | 103 | TRACE(L_DEBUG, "config: option %s=%s", var, val); 104 | } 105 | 106 | TRACE(L_DEBUG, "config: close file"); 107 | fclose(fp); 108 | 109 | return 0; 110 | } 111 | 112 | int removePID(char *filename) { 113 | if ( unlink(filename) != 0 ) { 114 | /* Don't show this is useless actually */ 115 | /* perror("unlink");*/ 116 | return -1; 117 | } 118 | return 0; 119 | } 120 | 121 | int writePID(char *filename) { 122 | FILE *fp = fopen(filename, "w"); 123 | if ( fp == 0 ) { 124 | perror("fopen"); 125 | return -1; 126 | } 127 | fprintf(fp, "%ld\n", (long)getpid()); 128 | fclose(fp); 129 | 130 | return 0; 131 | } 132 | 133 | 134 | 135 | /* Same function in unistd.h daemon */ 136 | void background() { 137 | #if _WIN32 138 | // do nothing for now... 139 | // FreeConsole ? 140 | #else 141 | pid_t pid, sid; 142 | 143 | 144 | /* Fork off the parent process */ 145 | pid = fork(); 146 | if (pid < 0) { 147 | exit(EXIT_FAILURE); 148 | } 149 | 150 | /* If we got a good PID, then 151 | we can exit the parent process. */ 152 | if (pid > 0) { 153 | exit(EXIT_SUCCESS); 154 | } 155 | 156 | /* Open any logs here */ 157 | /* Create a new SID for the child process */ 158 | sid = setsid(); 159 | if (sid < 0) { 160 | /* Log any failure */ 161 | exit(EXIT_FAILURE); 162 | } 163 | 164 | /* Change the current working directory */ 165 | if ((chdir("/")) < 0) { 166 | /* Log any failure here */ 167 | exit(EXIT_FAILURE); 168 | } 169 | 170 | /* Close out the standard file descriptors */ 171 | close(STDIN_FILENO); 172 | close(STDOUT_FILENO); 173 | close(STDERR_FILENO); 174 | #endif 175 | } 176 | 177 | /* Fast hack for secure strcpy, to lazy to check if is trully secure */ 178 | char *strncpy_sx(char *dest, const char *src, size_t n) { 179 | dest[n] = 0; 180 | char *s = strncpy(dest, src, n-1); 181 | return s; 182 | } 183 | -------------------------------------------------------------------------------- /src/configd-util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * configd-util.h 3 | * 4 | * Created on: 2011-04-03 5 | * Author: Hugo Caron 6 | * Email: 7 | * 8 | * Copyright (C) 2011 by Hugo Caron 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | #ifndef CONFIGD_UTIL__H 29 | #define CONFIGD_UTIL__H 30 | 31 | #include 32 | #include 33 | 34 | 35 | 36 | struct globalArgsServer_t { 37 | char fileauth[255]; // -a option 38 | char fileconfig[255]; // -f option 39 | char filelog[255]; // -l option 40 | char bindAddr[16]; // -b option 41 | unsigned int port; // -p option 42 | unsigned int verbosity; // -v option 43 | unsigned int daemon; // -d option 44 | unsigned int ssl; // -s option 45 | #ifdef HAVE_LIBSSL 46 | char filecert[255]; // -c option 47 | char filekey[255]; // -k option 48 | #endif 49 | unsigned int guest; 50 | char **inputFiles; // input files 51 | int numInputFiles; // # of input files 52 | } globalArgsServer; 53 | 54 | 55 | int loadConfigFile(char *filename, struct globalArgsServer_t *c); 56 | int writePID(char *filename); 57 | int removePID(char *filename); 58 | char *strncpy_sx(char *dest, const char *src, size_t n); 59 | 60 | #endif /* CONFIGD_UTIL__H */ 61 | -------------------------------------------------------------------------------- /src/libsocks/bor-util.c: -------------------------------------------------------------------------------- 1 | /* bor-util.c : Boite a Outil Reseau 2 | * 3 | * Edouard.Thiel@lif.univ-mrs.fr - 22/01/2009 - V 2.0 4 | * 5 | * This program is free software under the terms of the 6 | * GNU Lesser General Public License (LGPL) version 2.1. 7 | */ 8 | 9 | #include "bor-util.h" 10 | 11 | 12 | /* Affiche le message de perror en conservant la valeur de errno. 13 | */ 14 | void bor_perror (const char *funcname) 15 | { 16 | int e = errno; 17 | perror (funcname); 18 | errno = e; 19 | } 20 | 21 | 22 | /* Place le handler de signal void h(int) pour le signal sig avec sigaction(). 23 | Le signal est automatiquement masque pendant sa delivrance. 24 | Si options = 0, 25 | - les appels bloquants sont interrompus avec retour -1 et errno = EINTR. 26 | - le handler est rearme automatiquement apres chaque delivrance de signal. 27 | si options est une combinaison bit a bit de 28 | - SA_RESTART : les appels bloquants sont silencieusement repris. 29 | - SA_RESETHAND : le handler n'est pas rearme. 30 | Renvoie le resultat de sigaction. Verbeux. 31 | */ 32 | #ifndef _WIN32 33 | int bor_signal (int sig, void (*h)(int), int options) 34 | { 35 | int r; 36 | struct sigaction s; 37 | s.sa_handler = h; 38 | sigemptyset (&s.sa_mask); 39 | s.sa_flags = options; 40 | r = sigaction (sig, &s, NULL); 41 | if (r < 0) bor_perror (__func__); 42 | return r; 43 | } 44 | #endif 45 | 46 | 47 | /* Attachement d'une socket de domaine AF_UNIX a une adresse sockaddr_un 48 | Renvoie le resultat de bind(). Verbeux. 49 | */ 50 | int bor_bind_un (int soc, struct sockaddr_un *adr) 51 | { 52 | int r = bind (soc, (struct sockaddr *) adr, sizeof(struct sockaddr_un)); 53 | if (r < 0) bor_perror (__func__); 54 | return r; 55 | } 56 | 57 | 58 | /* Envoi d'un datagramme 59 | Renvoie le resultat de sendto. Verbeux. 60 | */ 61 | int bor_sendto_un (int soc, void *buf, size_t len, struct sockaddr_un *adr) 62 | { 63 | int r = sendto (soc, buf, len, 0, (struct sockaddr *) adr, 64 | sizeof(struct sockaddr_un)); 65 | if (r < 0) bor_perror (__func__); 66 | return r; 67 | } 68 | 69 | 70 | /* Reception d'un datagramme 71 | Renvoie le resultat de recvfrom. Verbeux. 72 | */ 73 | int bor_recvfrom_un (int soc, void *buf, size_t len, struct sockaddr_un *adr) 74 | { 75 | socklen_t adrlen = sizeof(struct sockaddr_un); 76 | int r = recvfrom (soc, buf, len, 0, (struct sockaddr *) adr, &adrlen); 77 | if (r < 0) bor_perror (__func__); 78 | return r; 79 | } 80 | 81 | 82 | /* Connexion a un serveur TCP/UN 83 | Renvoie le resultat de connect. Verbeux. 84 | */ 85 | int bor_connect_un (int soc, struct sockaddr_un *adr) 86 | { 87 | int r = connect (soc, (struct sockaddr *) adr, sizeof(struct sockaddr_un)); 88 | if (r < 0) bor_perror (__func__); 89 | return r; 90 | } 91 | 92 | 93 | /* Accepte une connexion en attente. 94 | Renvoie le resultat de accept. Verbeux. 95 | */ 96 | int bor_accept_un (int soc, struct sockaddr_un *adr) 97 | { 98 | socklen_t adrlen = sizeof(struct sockaddr_un); 99 | int r = accept (soc, (struct sockaddr *) adr, &adrlen); 100 | if (r < 0) bor_perror (__func__); 101 | return r; 102 | } 103 | 104 | 105 | /* Attachement d'une socket de domaine AF_INET a une adresse sockaddr_in 106 | Renvoie le resultat de bind(). Verbeux. 107 | */ 108 | int bor_bind_in (int soc, struct sockaddr_in *adr) 109 | { 110 | int r = bind (soc, (struct sockaddr *) adr, sizeof(struct sockaddr_in)); 111 | if (r < 0) bor_perror (__func__); 112 | return r; 113 | } 114 | 115 | 116 | /* Envoi d'un datagramme 117 | Renvoie le resultat de sendto. Verbeux. 118 | */ 119 | int bor_sendto_in (int soc, void *buf, size_t len, struct sockaddr_in *adr) 120 | { 121 | int r = sendto (soc, buf, len, 0, (struct sockaddr *) adr, 122 | sizeof(struct sockaddr_in)); 123 | if (r < 0) bor_perror (__func__); 124 | return r; 125 | } 126 | 127 | 128 | /* Reception d'un datagramme 129 | Renvoie le resultat de recvfrom. Verbeux. 130 | */ 131 | int bor_recvfrom_in (int soc, void *buf, size_t len, struct sockaddr_in *adr) 132 | { 133 | socklen_t adrlen = sizeof(struct sockaddr_in); 134 | int r = recvfrom (soc, buf, len, 0, (struct sockaddr *) adr, &adrlen); 135 | if (r < 0) bor_perror (__func__); 136 | return r; 137 | } 138 | 139 | 140 | /* Connexion a un serveur TCP/IP 141 | Renvoie le resultat de connect. Verbeux. 142 | */ 143 | int bor_connect_in (int soc, struct sockaddr_in *adr) 144 | { 145 | int r = connect (soc, (struct sockaddr *) adr, sizeof(struct sockaddr_in)); 146 | if (r < 0) bor_perror (__func__); 147 | return r; 148 | } 149 | 150 | 151 | /* Accepte une connexion en attente. 152 | Renvoie le resultat de accept. Verbeux. 153 | */ 154 | int bor_accept_in (int soc, struct sockaddr_in *adr) 155 | { 156 | socklen_t adrlen = sizeof(struct sockaddr_in); 157 | int r = accept (soc, (struct sockaddr *) adr, &adrlen); 158 | if (r < 0) bor_perror (__func__); 159 | return r; 160 | } 161 | 162 | 163 | /* Recuperation de l'adresse reelle et du port sous forme Network 164 | Renvoie le resultat de getsockname. Verbeux. 165 | */ 166 | int bor_getsockname_in (int soc, struct sockaddr_in *adr) 167 | { 168 | socklen_t adrlen = sizeof(struct sockaddr_in); 169 | int r = getsockname (soc, (struct sockaddr *) adr, &adrlen); 170 | if (r < 0) bor_perror (__func__); 171 | return r; 172 | } 173 | 174 | 175 | /* Renvoie l'adresse d'une chaine en memoire statique contenant l'adresse IPv4 176 | * sous la forme "a.b.c.d:port", de facon a pouvoir l'afficher. Silencieux. 177 | */ 178 | char *bor_adrtoa_in (struct sockaddr_in *adr) 179 | { 180 | static char s[32]; 181 | sprintf (s, "%s:%d", inet_ntoa(adr->sin_addr), ntohs(adr->sin_port)); 182 | return s; 183 | } 184 | 185 | -------------------------------------------------------------------------------- /src/libsocks/bor-util.h: -------------------------------------------------------------------------------- 1 | /* bor-util.h : Boite a Outil Reseau 2 | * 3 | * Edouard.Thiel@lif.univ-mrs.fr - 22/01/2009 - V 2.0 4 | * 5 | * This program is free software under the terms of the 6 | * GNU Lesser General Public License (LGPL) version 2.1. 7 | */ 8 | 9 | #ifndef BOR_UTIL__H 10 | #define BOR_UTIL__H 11 | 12 | #include /* printf, fgets */ 13 | #include /* exit */ 14 | #include /* strlen */ 15 | #include /* open, socket, bind, sendto, recvfrom, wait */ 16 | #include /* open */ 17 | #include /* open */ 18 | #include /* sigaction */ 19 | #include /* time, gettimeofday */ 20 | #include /* errno */ 21 | 22 | #include "unisocket.h" 23 | 24 | 25 | /* Compatibilite avec C++ */ 26 | #if defined(c_plusplus) && !defined(__cplusplus) 27 | #define __cplusplus 28 | #endif 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | 34 | /* UNIX_PATH_MAX pas toujours definie */ 35 | #ifndef UNIX_PATH_MAX 36 | #define UNIX_PATH_MAX 108 37 | #endif 38 | 39 | /* Prototypes */ 40 | void bor_perror (const char *funcname); 41 | int bor_signal (int sig, void (*h)(int), int options); 42 | 43 | int bor_bind_un (int soc, struct sockaddr_un *adr); 44 | int bor_sendto_un (int soc, void *buf, size_t len, struct sockaddr_un *adr); 45 | int bor_recvfrom_un (int soc, void *buf, size_t len, struct sockaddr_un *adr); 46 | int bor_connect_un (int soc, struct sockaddr_un *adr); 47 | int bor_accept_un (int soc, struct sockaddr_un *adr); 48 | 49 | int bor_bind_in (int soc, struct sockaddr_in *adr); 50 | int bor_sendto_in (int soc, void *buf, size_t len, struct sockaddr_in *adr); 51 | int bor_recvfrom_in (int soc, void *buf, size_t len, struct sockaddr_in *adr); 52 | int bor_connect_in (int soc, struct sockaddr_in *adr); 53 | int bor_accept_in (int soc, struct sockaddr_in *adr); 54 | int bor_getsockname_in (int soc, struct sockaddr_in *adr); 55 | char *bor_adrtoa_in (struct sockaddr_in *adr); 56 | 57 | 58 | /* Solution de repli pour __func__ */ 59 | #if __STDC_VERSION__ < 199901L 60 | # if __GNUC__ >= 2 61 | # define __func__ __FUNCTION__ 62 | # else 63 | # define __func__ "" 64 | # endif 65 | #endif 66 | 67 | /* Compatibilite avec C++ */ 68 | #ifdef __cplusplus 69 | } 70 | #endif 71 | 72 | #endif /* BOR_UTIL__H */ 73 | 74 | -------------------------------------------------------------------------------- /src/libsocks/client.c: -------------------------------------------------------------------------------- 1 | /* 2 | * client.c 3 | * 4 | * Created on: 2011-04-11 5 | * Author: Hugo Caron 6 | * Email: 7 | * 8 | * Copyright (C) 2011 by Hugo Caron 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | 29 | #include "client.h" 30 | 31 | #include "bor-util.h" 32 | 33 | void init_client (s_client *c, int id, int mode, s_socks_conf *conf) 34 | { 35 | c->id = id; 36 | /*c->mode = mode;*/ 37 | c->conf = conf; 38 | 39 | init_socket(&c->soc); 40 | init_socket(&c->soc_stream); 41 | init_socket(&c->soc_bind); 42 | 43 | init_socks(&c->socks, c->id, mode); 44 | init_socks(&c->socks_stream, c->id, (mode == M_DYNAMIC) ? M_DYNAMIC_CLIENT : mode); 45 | 46 | init_buffer(&c->buf); 47 | init_buffer(&c->stream_buf); 48 | } 49 | 50 | void disconnection(s_client *c) 51 | { 52 | if ( c->soc_stream.soc != -1 || c->soc_bind.soc != -1 || c->soc.soc != -1 ) 53 | TRACE(L_VERBOSE, "server [%d]: disconnected client ...", c->id); 54 | 55 | close_socket(&c->soc_stream); 56 | close_socket(&c->soc_bind); 57 | close_socket(&c->soc); 58 | 59 | init_client(c, c->id, c->socks.mode, c->conf); 60 | } 61 | 62 | int new_connection(int soc_ec, s_client *tc, int ssl) 63 | { 64 | int nc, soc_tmp; 65 | struct sockaddr_in adrC_tmp; 66 | 67 | TRACE(L_DEBUG, "server: connection in progress ..."); 68 | soc_tmp = bor_accept_in (soc_ec, &adrC_tmp); 69 | if (soc_tmp < 0) { 70 | return -1; 71 | } 72 | 73 | /* Search free space in tc[].soc */ 74 | for (nc = 0; nc < MAXCLI; nc++) 75 | if (tc[nc].soc.soc == -1) break; 76 | 77 | if (nc < MAXCLI) { 78 | init_client(&tc[nc], tc[nc].id, tc[nc].socks.mode, tc[nc].conf); 79 | tc[nc].soc.soc = soc_tmp; 80 | tc[nc].soc.con = 1; 81 | memcpy (&tc[nc].soc.adrC, &adrC_tmp, sizeof(struct sockaddr_in)); 82 | TRACE(L_VERBOSE, "server [%d]: established connection with %s", 83 | nc, bor_adrtoa_in(&adrC_tmp)); 84 | 85 | #ifdef HAVE_LIBSSL 86 | /* Init SSL here 87 | */ 88 | if ( ssl == 1 ) { 89 | TRACE(L_DEBUG, "server [%d]: socks5 enable ssl ...", nc); 90 | tc[nc].soc.ssl = ssl_neogiciate_server(tc[nc].soc.soc); 91 | if ( tc[nc].soc.ssl == NULL ) { 92 | ERROR(L_VERBOSE, "server [%d]: ssl error", nc); 93 | disconnection(&tc[nc]); 94 | return -1; 95 | } 96 | TRACE(L_DEBUG, "server [%d]: ssl ok.", nc); 97 | set_non_blocking(tc[nc].soc.soc); 98 | } 99 | #endif /* HAVE_LIBSSL */ 100 | 101 | return nc; 102 | //append_log_client(&tc[nc], "%s", bor_adrtoa_in(&adrC_tmp)); 103 | //set_non_blocking(tc[nc].soc.soc); 104 | } else { 105 | CLOSE_SOCKET(soc_tmp); 106 | ERROR (L_NOTICE, "server: %s connection refused : too many clients!", 107 | bor_adrtoa_in(&adrC_tmp)); 108 | return -1; 109 | } 110 | } 111 | 112 | 113 | -------------------------------------------------------------------------------- /src/libsocks/client.h: -------------------------------------------------------------------------------- 1 | /* 2 | * client.h 3 | * 4 | * Created on: 2011-04-11 5 | * Author: Hugo Caron 6 | * Email: 7 | * 8 | * Copyright (C) 2011 by Hugo Caron 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | #ifndef CLIENT__H 29 | #define CLIENT__H 30 | 31 | #include "socks-common.h" 32 | 33 | #define MAXCLI 512 34 | #define BUFFER_SIZE 4096 35 | 36 | typedef struct { 37 | int id; 38 | 39 | s_socket soc; 40 | s_socks socks; 41 | s_buffer buf; 42 | 43 | s_socket soc_stream; 44 | s_socks socks_stream; 45 | s_buffer stream_buf; 46 | 47 | s_socket soc_bind; 48 | s_socks_conf *conf; 49 | } s_client; 50 | 51 | 52 | void init_client (s_client *c, int id, int mode, s_socks_conf *conf); 53 | void disconnection(s_client *c); 54 | int new_connection(int soc_ec, s_client *tc, int ssl); 55 | 56 | 57 | 58 | #endif /* CLIENT__H */ 59 | -------------------------------------------------------------------------------- /src/libsocks/log-util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * log-util.c 3 | * 4 | * Created on: 2011-04-03 5 | * Author: Hugo Caron 6 | * Email: 7 | * 8 | * Copyright (C) 2011 by Hugo Caron 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | #include "output-util.h" 29 | #include "bor-util.h" 30 | #include "socks-common.h" 31 | 32 | #include 33 | #include 34 | 35 | FILE *fpLog = 0; 36 | 37 | int open_log(char *filename) { 38 | TRACE(L_DEBUG, "log: open file %s ...", filename); 39 | 40 | fpLog = fopen(filename, "a+"); 41 | if ( fpLog == 0 ) { 42 | perror("fopen log file"); 43 | return -1; 44 | } 45 | 46 | return 0; 47 | } 48 | 49 | void close_log() { 50 | if ( fpLog != 0 ) { 51 | fclose(fpLog); 52 | TRACE(L_DEBUG, "log: close file"); 53 | } 54 | } 55 | 56 | void write_log(s_socks *s, s_socket *soc, s_socket *stream) { 57 | time_t tim=time(NULL); 58 | struct tm *now=localtime(&tim); 59 | char *cmd = (s->cmd == 0x02) ? "BIND" : "CONNECT"; 60 | char ipcli[32], ipsrc[32]; 61 | sprintf(ipcli, "%s", bor_adrtoa_in(&soc->adrC)); 62 | sprintf(ipsrc, "%s", bor_adrtoa_in(&stream->adrS)); 63 | 64 | 65 | TRACE(L_NOTICE, "%d/%02d/%02d %02d:%02d:%02d | %21s <-> %21s | %s | %s", 66 | now->tm_year+1900, now->tm_mon+1, now->tm_mday, 67 | now->tm_hour, now->tm_min, now->tm_sec, 68 | ipcli, ipsrc, 69 | cmd, s->uname); 70 | 71 | if ( fpLog != 0 ) { 72 | fprintf(fpLog, "%d/%02d/%02d %02d:%02d:%02d | %21s <-> %21s | %s | %s\n", 73 | now->tm_year+1900, now->tm_mon+1, now->tm_mday, 74 | now->tm_hour, now->tm_min, now->tm_sec, 75 | ipcli, ipsrc, 76 | cmd, s->uname); 77 | 78 | fflush(fpLog); 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/libsocks/log-util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * log-util.h 3 | * 4 | * Created on: 2011-04-03 5 | * Author: Hugo Caron 6 | * Email: 7 | * 8 | * Copyright (C) 2011 by Hugo Caron 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | #ifndef LOG_UTILS__H 29 | #define LOG_UTILS__H 30 | 31 | #include "socks-common.h" 32 | 33 | int open_log(char *filename); 34 | void close_log(); 35 | void write_log(s_socks *s, s_socket *soc, s_socket *stream); 36 | 37 | 38 | #endif /* LOG_UTILS__H */ 39 | -------------------------------------------------------------------------------- /src/libsocks/net-util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * net-util.c 3 | * 4 | * Created on: 2011-03-30 5 | * Author: Hugo Caron 6 | * Email: 7 | * 8 | * Copyright (C) 2011 by Hugo Caron 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | #include "net-util.h" 29 | #include "bor-util.h" 30 | #include "output-util.h" 31 | 32 | int new_socket_tcpip(int port, struct sockaddr_in *addr) { 33 | int soc; 34 | /* Internet domain socket creation in connected mode */ 35 | soc = socket(AF_INET, SOCK_STREAM, 0); 36 | if ( soc < 0 ) { 37 | perror("socket"); 38 | return -1; 39 | } 40 | 41 | /* Making local address */ 42 | addr->sin_family = AF_INET; 43 | addr->sin_port = htons(port); 44 | /* All Local Addresses */ 45 | addr->sin_addr.s_addr = htonl(INADDR_ANY); 46 | 47 | TRACE(L_DEBUG, "socket: attachment to a local socket port ..."); 48 | if ( bor_bind_in(soc, addr) < 0 ) { 49 | CLOSE_SOCKET(soc); 50 | return -1; 51 | } 52 | 53 | /* Recovering the client port */ 54 | if ( bor_getsockname_in(soc, addr) < 0 ) { 55 | CLOSE_SOCKET(soc); 56 | return -1; 57 | } 58 | 59 | TRACE(L_DEBUG, "socket: local port %d open", ntohs(addr->sin_port)); 60 | return soc; 61 | } 62 | 63 | int build_addr(char ip[4], int port, struct sockaddr_in *addr) { 64 | addr->sin_family = AF_INET; 65 | addr->sin_port = htons(port); 66 | memcpy(&addr->sin_addr.s_addr, ip, 4); 67 | return 1; 68 | } 69 | 70 | int build_addr_server(char *name, int port, struct sockaddr_in *addr) { 71 | struct hostent *hp; 72 | addr->sin_family = AF_INET; 73 | addr->sin_port = htons(port); 74 | TRACE(L_DEBUG, "dns: server address resolution %s ...", name); 75 | if( ( hp = gethostbyname(name) ) == NULL ) { 76 | #ifdef _WIN32 77 | ERROR(L_DEBUG, "gethostbyname failed with code %d", WSAGetLastError()); 78 | #else 79 | herror("gethostbyname"); 80 | #endif 81 | return -1; 82 | } 83 | memcpy(&addr->sin_addr.s_addr, hp->h_addr, hp->h_length); 84 | return 1; 85 | } 86 | 87 | static char* _uitoa(unsigned int n, char (*digits)[21]) { 88 | char *p = &(*digits)[sizeof(*digits)-1]; 89 | 90 | *p = '\0'; 91 | do { 92 | p--; 93 | *p = '0' + (n%10); 94 | n = n / 10; 95 | } while (n>0); 96 | 97 | return p; 98 | } 99 | 100 | int new_listen_socket (const char *bindAddr, int nport, int backlog, struct sockaddr_in *addrS) { 101 | 102 | int soc_ec; 103 | int error; 104 | char portstring[21]; 105 | 106 | struct addrinfo hints = {0,}; 107 | struct addrinfo *res = NULL; 108 | struct addrinfo *rp = NULL; 109 | 110 | hints.ai_family = AF_INET; 111 | hints.ai_socktype = SOCK_STREAM; 112 | hints.ai_protocol = 0; 113 | hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG | AI_PASSIVE | AI_NUMERICSERV; 114 | 115 | error = getaddrinfo(bindAddr, _uitoa(nport, &portstring), &hints, &res); 116 | if (0 != error) { 117 | ERROR(L_NOTICE, "server: resolution error in getaddrinfo: %s\n", gai_strerror(error)); 118 | return -1; 119 | } 120 | 121 | for (rp = res; rp != NULL; rp = rp->ai_next) { 122 | soc_ec = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); 123 | if (soc_ec == -1) continue; 124 | 125 | if (bind(soc_ec, rp->ai_addr, rp->ai_addrlen) == 0) { 126 | memcpy(addrS, rp->ai_addr, sizeof(*addrS)); 127 | break; 128 | } 129 | 130 | CLOSE_SOCKET(soc_ec); 131 | } 132 | 133 | freeaddrinfo(res); 134 | res = NULL; 135 | 136 | if (rp == NULL) { 137 | ERROR(L_NOTICE, "server: could not bind any address."); 138 | return -1; 139 | } 140 | 141 | /* Recovery of the port as network endian */ 142 | if (bor_getsockname_in (soc_ec, addrS) < 0) 143 | { 144 | perror ("getsockname ip"); 145 | CLOSE_SOCKET(soc_ec); 146 | return -1; 147 | } 148 | TRACE(L_DEBUG, "server: port %d open", ntohs(addrS->sin_port)); 149 | 150 | /* Ouverture du service ; le second param est le nb max de connexions 151 | pendantes, limite a SOMAXCONN (=128 sur Linux) */ 152 | if (listen (soc_ec, backlog) < 0) { 153 | perror ("listen"); 154 | return -1; 155 | } 156 | TRACE(L_NOTICE, "server: listening on %s", bor_adrtoa_in (addrS)); 157 | 158 | return soc_ec; 159 | } 160 | 161 | int new_client_socket_no_ip(char ip[4], uint16_t nport, struct sockaddr_in *addrC, 162 | struct sockaddr_in *addrS) { 163 | int soc = new_socket_tcpip(0, addrC); 164 | 165 | if ( soc < 0 ) { 166 | return -1; 167 | } 168 | set_non_blocking(soc); 169 | if ( build_addr(ip, nport, addrS) < 0 ) { 170 | CLOSE_SOCKET(soc); 171 | return -1; 172 | } 173 | 174 | TRACE(L_VERBOSE, "client: server connection on %s:%d ...", 175 | inet_ntoa(addrS->sin_addr), ntohs(addrS->sin_port)); 176 | connect (soc, (struct sockaddr *) addrS, sizeof(struct sockaddr_in)); 177 | 178 | return soc; 179 | } 180 | 181 | int new_client_socket_no(char *nameS, uint16_t nport, struct sockaddr_in *addrC, 182 | struct sockaddr_in *addrS) { 183 | int soc = new_socket_tcpip(0, addrC); 184 | 185 | if ( soc < 0 ) { 186 | return -1; 187 | } 188 | set_non_blocking(soc); 189 | if ( build_addr_server(nameS, nport, addrS) < 0 ) { 190 | CLOSE_SOCKET(soc); 191 | return -1; 192 | } 193 | 194 | TRACE(L_VERBOSE, "client: server connection on %s:%d ...", 195 | nameS, ntohs(addrS->sin_port)); 196 | connect (soc, (struct sockaddr *) addrS, sizeof(struct sockaddr_in)); 197 | 198 | return soc; 199 | } 200 | 201 | int new_client_socket(char *nameS, uint16_t nport, 202 | struct sockaddr_in *addrC, struct sockaddr_in *addrS) { 203 | int soc; 204 | /*struct sockaddr_in addrS, addrC;*/ 205 | 206 | soc = new_socket_tcpip(0, addrC); 207 | if ( soc < 0 ) { 208 | return -1; 209 | } 210 | 211 | if ( build_addr_server(nameS, nport, addrS) < 0 ) { 212 | CLOSE_SOCKET(soc); 213 | return -1; 214 | } 215 | 216 | TRACE(L_VERBOSE, "client: server connection on %s:%d ...", 217 | nameS, ntohs(addrS->sin_port)); 218 | if ( bor_connect_in(soc, addrS) < 0 ) { 219 | CLOSE_SOCKET(soc); 220 | return -1; 221 | } 222 | 223 | /* Recovering the client address and port after the connection*/ 224 | if ( bor_getsockname_in(soc, addrC) < 0 ) { 225 | CLOSE_SOCKET(soc); 226 | return -1; 227 | } 228 | 229 | //TRACE(L_VERBOSE, "client: established connection ..."); 230 | return soc; 231 | } 232 | 233 | int set_blocking(int fd) { 234 | int r = 0; 235 | return r; 236 | } 237 | 238 | /* Find on the board don't remember were, 239 | * I just add error handling with perror 240 | */ 241 | int set_non_blocking(int fd) { 242 | int flags, r; 243 | 244 | /* If they have O_NONBLOCK, use the Posix way to do it */ 245 | #if defined(O_NONBLOCK) 246 | /* FIXME: O_NONBLOCK is defined but broken on SunOS 4.1.x and AIX 3.2.5. */ 247 | if (-1 == (flags = fcntl(fd, F_GETFL, 0))) 248 | flags = 0; 249 | r = fcntl(fd, F_SETFL, flags | O_NONBLOCK); 250 | if (r < 0) bor_perror (__func__); 251 | return r; 252 | #else 253 | /* Otherwise, use the old way of doing it */ 254 | flags = 1; 255 | #ifndef _WIN32 256 | r = ioctl(fd, FIOBIO, &flags); 257 | #else 258 | r = ioctlsocket(fd, FIONBIO, &flags); 259 | #endif 260 | if (r < 0) bor_perror (__func__); 261 | return r; 262 | #endif 263 | } 264 | -------------------------------------------------------------------------------- /src/libsocks/net-util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * net-util.h 3 | * 4 | * Created on: 2011-03-30 5 | * Author: Hugo Caron 6 | * Email: 7 | * 8 | * Copyright (C) 2011 by Hugo Caron 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | 29 | #ifndef NET_UTIL__H 30 | #define NET_UTIL__H 31 | 32 | 33 | #include "unisocket.h" 34 | #include 35 | 36 | 37 | /* Prototypes */ 38 | int new_socket_tcpip(int port, struct sockaddr_in *addr); 39 | int build_addr_server(char *name, int port, struct sockaddr_in *addr); 40 | int new_listen_socket (const char *name, int nport, int maxpend, struct sockaddr_in *addrS); 41 | int new_client_socket(char *nameS, uint16_t nport, 42 | struct sockaddr_in *addrC, struct sockaddr_in *addrS); 43 | 44 | int new_client_socket_no(char *nameS, uint16_t nport, struct sockaddr_in *addrC, 45 | struct sockaddr_in *addrS); 46 | 47 | int new_client_socket_no_ip(char ip[4], uint16_t nport, struct sockaddr_in *addrC, 48 | struct sockaddr_in *addrS); 49 | 50 | int set_blocking(int fd); 51 | int set_non_blocking(int fd); 52 | 53 | 54 | 55 | #endif /* NET_UTIL__H */ 56 | 57 | -------------------------------------------------------------------------------- /src/libsocks/output-util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * output-util.c 3 | * 4 | * Created on: 2011-04-03 5 | * Author: Hugo Caron 6 | * Email: 7 | * 8 | * Copyright (C) 2011 by Hugo Caron 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | #include "output-util.h" 29 | 30 | #include 31 | #include 32 | #include 33 | #include /* isspace */ 34 | 35 | 36 | int verbosity = 0; 37 | 38 | void ERROR(int level, char *template, ...) { 39 | va_list ap; 40 | va_start(ap, template); 41 | if ( level <= verbosity ) { 42 | vfprintf(stderr, template, ap); 43 | printf("\n"); 44 | } 45 | va_end(ap); 46 | } 47 | 48 | void TRACE(int level, char *template, ...) { 49 | va_list ap; 50 | va_start(ap, template); 51 | if ( level <= verbosity ) { 52 | vfprintf(stdout, template, ap); 53 | printf("\n"); 54 | } 55 | va_end(ap); 56 | } 57 | 58 | void DUMP(const char *s, size_t n) { 59 | unsigned int i; 60 | 61 | for (i=0; i < n; i++) 62 | printf ("0x%x ", s[i]); 63 | 64 | printf ("\n"); 65 | } 66 | 67 | void trim(char * s) { 68 | char *p = s; 69 | int l = strlen(p); 70 | 71 | while(isspace(p[l - 1])) p[--l] = 0; 72 | while(*p && isspace(*p)) ++p, --l; 73 | 74 | memmove(s, p, l + 1); 75 | } 76 | -------------------------------------------------------------------------------- /src/libsocks/output-util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * output-util.h 3 | * 4 | * Created on: 2011-04-03 5 | * Author: Hugo Caron 6 | * Email: 7 | * 8 | * Copyright (C) 2011 by Hugo Caron 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | #ifndef OUTPUT_UTIL__H 29 | #define OUTPUT_UTIL__H 30 | 31 | #include 32 | #undef ERROR 33 | 34 | /* Global variable */ 35 | extern int verbosity; 36 | 37 | /* Verbosity level */ 38 | enum { 39 | L_NOTICE, 40 | L_VERBOSE, 41 | L_DEBUG 42 | }; 43 | 44 | void TRACE(int level, char *template, ...); 45 | void ERROR(int level, char *template, ...); 46 | void DUMP (const char *s, size_t n); 47 | void trim(char * s); 48 | 49 | #endif /* OUTPUT_UTIL__H */ 50 | -------------------------------------------------------------------------------- /src/libsocks/socks-common.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "socks-common.h" 3 | 4 | int buf_empty(s_buffer *buf) { 5 | return ( (buf->b - buf->a) == 0 ); 6 | } 7 | 8 | int buf_size(s_buffer *buf) { 9 | return (buf->b - buf->a); 10 | } 11 | 12 | int buf_free(s_buffer *buf) { 13 | return sizeof(buf->data) - buf->b - 1; 14 | } 15 | 16 | /* Return -1 error 17 | * Return 0 need to write again 18 | * Reutrn 1 all data was write 19 | */ 20 | int write_socks(s_socket *s, s_buffer *buf) { 21 | int k; 22 | #ifdef HAVE_LIBSSL 23 | if ( s->ssl != NULL ) { 24 | k = SSL_write(s->ssl, buf->data + buf->a, buf_size(buf)); 25 | if (k < 0) { 26 | perror("write socks"); 27 | return -1; 28 | } 29 | buf->a += k; 30 | return buf_empty(buf); 31 | } 32 | #endif 33 | k = send(s->soc, buf->data + buf->a, buf_size(buf), 0); 34 | if (k < 0) { 35 | perror("write socks"); 36 | return -1; 37 | } 38 | buf->a += k; 39 | return buf_empty(buf); 40 | } 41 | 42 | /* Return -1 error 43 | * Return 0 need to read again 44 | * Reutrn 1 have read size >= minsize 45 | */ 46 | int read_socks(s_socket *s, s_buffer *buf, size_t minsize) { 47 | int k; 48 | #ifdef HAVE_LIBSSL 49 | if ( s->ssl != NULL ) { 50 | k = SSL_read(s->ssl, buf->data + buf->b, buf_free(buf)); 51 | if (k < 0) { 52 | perror("read socks"); 53 | return -1; 54 | } 55 | if (k == 0) { 56 | return -1; 57 | } 58 | buf->b += k; 59 | return (buf->b >= minsize); 60 | } 61 | #endif 62 | k = recv(s->soc, buf->data + buf->b, buf_free(buf), 0); 63 | if (k < 0) { 64 | #ifdef _WIN32 65 | ERROR(L_NOTICE, "read socks failed with %d", WSAGetLastError()); 66 | #else 67 | perror("read socks"); 68 | #endif 69 | return -2; 70 | } 71 | if (k == 0) { 72 | return -1; 73 | } 74 | buf->b += k; 75 | return (buf->b >= minsize); 76 | } 77 | 78 | void init_buffer(s_buffer *buf) { 79 | buf->data[0] = 0; 80 | buf->a = 0; 81 | buf->b = 0; 82 | } 83 | 84 | void init_socket(s_socket *s) { 85 | s->soc = -1; 86 | s->con = 0; 87 | #ifdef HAVE_LIBSSL 88 | s->ssl= NULL; 89 | s->want_ssl= -1; 90 | #endif 91 | } 92 | 93 | void init_socks(s_socks *s, int id, int mode) { 94 | s->id = id; 95 | s->mode = mode; /* Socks mode */ 96 | switch(s->mode) { 97 | case M_CLIENT: 98 | s->state = S_W_VER; 99 | break; 100 | case M_SERVER: 101 | s->state = S_R_VER; 102 | break; 103 | case M_DYNAMIC: 104 | s->state = S_R_VER; 105 | break; 106 | case M_DYNAMIC_CLIENT: 107 | s->state = S_W_VER; 108 | break; 109 | default: 110 | s->state = -1; /* Socks state */ 111 | break; 112 | } 113 | 114 | s->version = -1; /* Version choose, default -1 */ 115 | s->method = -1; /* Authentication method choose, default -1 */ 116 | s->auth = 0; /* Authenticate flag, default 0 */ 117 | s->connected = 0; /* Connected flag, default 0 */ 118 | s->listen = 0; /* Listen flag in bind mode, default 0, 119 | * if -1 error when accept */ 120 | s->cmd = 0; /* Socks command request */ 121 | 122 | s->uname[0] = 0; 123 | } 124 | 125 | 126 | void close_socket(s_socket *s) { 127 | if ( s->soc != -1 ) CLOSE_SOCKET(s->soc); 128 | s->soc = -1; 129 | 130 | #ifdef HAVE_LIBSSL 131 | if ( s->ssl != NULL ) ssl_close(s->ssl); 132 | s->ssl= NULL; 133 | #endif 134 | } 135 | -------------------------------------------------------------------------------- /src/libsocks/socks-common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * socks5-common.h 3 | * 4 | * Created on: 2011-04-11 5 | * Author: Hugo Caron 6 | * Email: 7 | * 8 | * Copyright (C) 2011 by Hugo Caron 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | #ifndef SOCKS_COMMON__H 29 | #define SOCKS_COMMON__H 30 | 31 | 32 | #include 33 | #include 34 | 35 | #include "unisocket.h" 36 | #include "output-util.h" 37 | 38 | 39 | #ifdef HAVE_LIBSSL 40 | #include "ssl-util.h" 41 | #endif 42 | 43 | #define SOCKS4_V 0x04 44 | #define SOCKS5_V 0x05 45 | 46 | 47 | typedef int (*pcheck_auth)(char *uname, char *passwd); 48 | 49 | /* Socks mode */ 50 | enum { 51 | M_SERVER, /* Server mode used by ssocksd */ 52 | 53 | M_CLIENT, /* Client mode used by nsocks and ssocks */ 54 | 55 | M_DYNAMIC, /* Run a server and listen, when it receive data 56 | * it transmit it to a another socks server, 57 | * used by ssocks */ 58 | M_DYNAMIC_CLIENT, 59 | }; 60 | 61 | /* Socks state */ 62 | enum { 63 | S_R_VER, /* Read version */ 64 | S_W_VER, /* Write version */ 65 | S_R_VER_ACK, /* Read version ACK */ 66 | S_W_VER_ACK, /* Write version ACK */ 67 | 68 | S_R_AUTH, /* Read authentication */ 69 | S_W_AUTH, /* Write authentication ACK */ 70 | S_R_AUTH_ACK, /* Read authentication */ 71 | S_W_AUTH_ACK, /* Write authentication ACK */ 72 | 73 | S_R_REQ, /* Read authentication */ 74 | S_W_REQ, /* Write authentication */ 75 | S_R_REQ_ACK, /* Read authentication ACK */ 76 | S_W_REQ_ACK, /* Write authentication ACK */ 77 | 78 | S_W_SSL_NEGO, /* Read SSL negociation */ 79 | S_R_SSL_NEGO, /* Write SSL negociation */ 80 | 81 | S_REPLY, /* Read on a socket, write a another */ 82 | 83 | S_WAIT /* Nothing to do just wait */ 84 | }; 85 | 86 | /* Configuration type enumeration */ 87 | enum { 88 | CONFIG_SERVER, 89 | CONFIG_SERVER_DYNA, 90 | CONFIG_CLIENT 91 | }; 92 | 93 | /* Socket structure need to used socket and ssl 94 | * side by side in the same code 95 | */ 96 | typedef struct { 97 | int soc; /* Socket */ 98 | int con; /* Connected flag to used with non blocking connect */ 99 | #ifdef HAVE_LIBSSL 100 | SSL *ssl; /* SSL socket */ 101 | #endif 102 | int want_ssl; /* Trick for dynamic mode to know you need ssl*/ 103 | 104 | struct sockaddr_in adrS; /* Socket server info */ 105 | struct sockaddr_in adrC; /* Socket client info */ 106 | } s_socket; 107 | 108 | /* Socks5 information used to build packet 109 | */ 110 | typedef struct { 111 | int id; 112 | int mode; /* Socks mode */ 113 | int state; /* Socks state */ 114 | int version; /* Version choose, default -1 */ 115 | int method; /* Authentication method choose, default -1 */ 116 | int auth; /* Authenticate flag, default 0 */ 117 | int connected; /* Connected flag, default 0 */ 118 | int listen; /* Listen flag in bind mode, default 0, 119 | * if -1 error when accept */ 120 | int cmd; /* Socks command request */ 121 | char uname[256]; 122 | } s_socks; 123 | 124 | 125 | /* Socks5 server configuration */ 126 | /*typedef struct { 127 | 128 | }s_socks_serv_config;*/ 129 | #define CMD_CONNECT 0x01 130 | #define CMD_BIND 0x02 131 | #define CMD_UDP 0x03 132 | 133 | /* Socks5 client configuration */ 134 | typedef struct { 135 | int cmd; /* CMD_CONNECT, CMD_BIND, CMD_UDP */ 136 | char *host; /* Asking host */ 137 | int port; /* Asking port */ 138 | int listen; /* Asking bind port */ 139 | 140 | char *sockshost; /* Socks5 destination host */ 141 | int socksport; /* Socks5 port host */ 142 | 143 | int version; /* Socks version */ 144 | 145 | char *username; /* Socks5 username */ 146 | char *password; /* Socks5 password */ 147 | 148 | /* Set internally */ 149 | int loop; /* Client loop */ 150 | char *allowed_method; /* Accepted method, 151 | * last need to be NULL */ 152 | size_t n_allowed_method; 153 | 154 | } s_socks_client_config; 155 | 156 | typedef struct { 157 | size_t n_allowed_version; 158 | char *allowed_version; /* Accepted version*/ 159 | 160 | char *allowed_method; /* Accepted method */ 161 | size_t n_allowed_method; 162 | 163 | pcheck_auth check_auth; 164 | } s_socks_server_config; 165 | 166 | /* Socks5 configuration 167 | */ 168 | typedef struct { 169 | int type; /* CONFIG_SERVER, CONFIG_SERVER_DYNA, CONFIG_CLIENT */ 170 | struct { 171 | s_socks_client_config *cli; 172 | s_socks_server_config *srv; 173 | } config; 174 | } s_socks_conf; 175 | 176 | 177 | /* Buffer definition 178 | */ 179 | typedef struct { 180 | char data[4096]; 181 | size_t pos, a, b; 182 | } s_buffer; 183 | 184 | /* Macro to read and write properly 185 | */ 186 | #define WRITE_DISP(k, soc, buf) \ 187 | k = write_socks(soc, buf); \ 188 | if (k < 0){ /* close_socket(soc); */ break; } /* Error */ \ 189 | if (k == 0) { break; } /* Need to write again */ \ 190 | init_buffer(buf); 191 | 192 | #define READ_DISP(k, soc, buf, minsize) \ 193 | (k) = read_socks(soc, buf, minsize); \ 194 | if ((k) < 0){ /* close_socket(soc); */ break; } /* Error */ \ 195 | if ((k) == 0) { break; } /* Need to read again */ 196 | 197 | #define PEEK_DISP(buf, minsize) (buf_size((buf)) >= (minsize)) 198 | 199 | /* Prototypes 200 | */ 201 | int buf_empty(s_buffer *buf); 202 | int buf_size(s_buffer *buf); 203 | int buf_free(s_buffer *buf); 204 | 205 | int read_socks(s_socket *s, s_buffer *buf, size_t minsize); 206 | int write_socks(s_socket *s, s_buffer *buf); 207 | 208 | 209 | void init_buffer(s_buffer *buf); 210 | void init_socket(s_socket *s); 211 | void init_socks(s_socks *s, int id, int mode); 212 | 213 | void close_socket(s_socket *s); 214 | 215 | /* From here packet definition used to manipulate packet 216 | * --------------------------------------------------------------------- 217 | */ 218 | 219 | /* Socks5 version packet */ 220 | typedef struct { 221 | char ver; 222 | char nmethods; 223 | char methods[5]; 224 | } Socks5Version; 225 | 226 | /* Socks5 version packet ACK */ 227 | #pragma pack(push, 2) 228 | typedef struct { 229 | char ver; 230 | char method; 231 | } Socks5VersionACK; 232 | #pragma pack(pop) 233 | 234 | /* Socks5 authentication packet */ 235 | typedef struct { 236 | char ver; 237 | char ulen; 238 | char uname[256]; 239 | char plen; 240 | char passwd[256]; 241 | } Socks5Auth; 242 | 243 | /* Socks5 authentication packet ACK */ 244 | #pragma pack(push, 2) 245 | typedef struct { 246 | char ver; 247 | char status; 248 | } Socks5AuthACK; 249 | #pragma pack(pop) 250 | 251 | /* Socks5 request packet */ 252 | typedef struct { 253 | char ver; 254 | char cmd; 255 | char rsv; 256 | char atyp; 257 | /*char dstadr; 258 | unsigned short dstport;*/ 259 | } Socks5Req; 260 | 261 | /* Socks5 request packet ACK 262 | * Need to change alignment 4 -> 2 else sizeof 12 instead of 10 */ 263 | #pragma pack(push, 2) /* Change alignment 4 -> 2 */ 264 | typedef struct { 265 | char ver; 266 | char rep; 267 | char rsv; 268 | char atyp; 269 | struct in_addr bndaddr; /* uint32_t */ 270 | uint16_t bndport; 271 | } Socks5ReqACK; 272 | 273 | 274 | typedef struct { 275 | char ver; 276 | char cmd; 277 | uint16_t dstport; 278 | char dstadr[4]; 279 | char *uid; 280 | } Socks4Req; 281 | 282 | typedef struct { 283 | char ver; /* Need to be null */ 284 | char rep; 285 | char ign[2]; 286 | char ign2[4]; 287 | } Socks4ReqAck; 288 | 289 | #pragma pack(pop) /* End of change alignment */ 290 | 291 | #endif /* SOCKS5_COMMON__H */ 292 | -------------------------------------------------------------------------------- /src/libsocks/socks4.c: -------------------------------------------------------------------------------- 1 | /* 2 | * socks4.c 3 | * 4 | * Created on: 2011-04-11 5 | * Author: Hugo Caron 6 | * Email: 7 | * 8 | * Copyright (C) 2011 by Hugo Caron 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | #include "socks4.h" 29 | #include "bor-util.h" 30 | #include "net-util.h" 31 | 32 | #include 33 | #include 34 | 35 | 36 | int test_request4(s_socks *s, s_socket *stream, s_socket *bind, 37 | s_socks_conf *c, s_buffer *buf) 38 | { 39 | Socks4Req req; 40 | TRACE(L_DEBUG, "server [%d]: testing client request ...", 41 | s->id); 42 | 43 | uint16_t port = 0; 44 | 45 | /* Rebuild the packet but don't extract 46 | * DST.ADDR and DST.PORT in Socks5Req struct */ 47 | memcpy(&req, buf->data, sizeof(Socks4Req)); 48 | TRACE(L_DEBUG, "server [%d]: v0x%x, cmd 0x%x,", 49 | s->id, req.ver, 50 | req.cmd ); 51 | 52 | /* Save the request cmd */ 53 | s->cmd = req.cmd; 54 | 55 | /* CMD: 56 | * - CONNECT X'01' 57 | * - BIND X'02' 58 | * - UDP ASSOCIATE X'03' 59 | * 60 | * Open or bind connection here 61 | */ 62 | switch(req.cmd) { 63 | case 0x01: /* TCP/IP Stream connection */ 64 | stream->soc = new_client_socket_no_ip(req.dstadr, 65 | ntohs(req.dstport), &stream->adrC, &stream->adrS); 66 | if ( stream->soc < 0 ) { 67 | return -3; 68 | } 69 | break; 70 | case 0x02: /* TCP/IP port binding */ 71 | bind->soc = new_listen_socket(NULL, req.dstport, 10, &bind->adrC); 72 | if ( bind->soc >= 0 ) { 73 | s->connected = 0; 74 | s->listen = 1; 75 | } 76 | 77 | break; 78 | /* TODO: udp support */ 79 | default : 80 | ERROR(L_NOTICE, "server [%d]: doesn't support udp", 81 | s->id); 82 | return -2; 83 | } 84 | 85 | return 0; 86 | } 87 | 88 | void build_request_ack4(s_socks *s, s_socks_conf *c, 89 | s_socket *stream, s_socket *bind, s_buffer *buf) 90 | { 91 | 92 | Socks4ReqAck res; 93 | #ifdef _WIN32 94 | char k; 95 | #else 96 | int k; 97 | #endif 98 | res.ver = 0x00; 99 | socklen_t socklen = sizeof(int); 100 | 101 | init_buffer(buf); 102 | 103 | switch(s->cmd) { 104 | case 0x01: 105 | /* 0x00 succeeded, 0x01 general SOCKS failure ... */ 106 | 107 | if ( getsockopt(stream->soc, SOL_SOCKET, SO_ERROR, &k, &socklen) < 0) { 108 | perror("getsockopt"); 109 | close_socket(stream); 110 | s->connected = 0; 111 | res.rep = 0x5b; 112 | break; 113 | } 114 | 115 | if (k != 0) { 116 | ERROR(L_VERBOSE, "client: error %d", k); 117 | close_socket(stream); 118 | s->connected = 0; 119 | res.rep = 0x5b; 120 | break; 121 | } 122 | 123 | /* Recovering the client address and port after the connection*/ 124 | if ( bor_getsockname_in(stream->soc, &stream->adrC) < 0 ) { 125 | close_socket(stream); 126 | s->connected = 0; 127 | res.rep = 0x5b; 128 | break; 129 | } 130 | 131 | /* In the reply to a CONNECT, BND.PORT contains 132 | * the port number that the server assigned to 133 | * connect to the target host, while BND.ADDR 134 | * contains the associated IP address. */ 135 | res.rep = 0x5a; 136 | s->connected = 1; 137 | /*memcpy(&res.bndaddr, &stream->adrC.sin_addr.s_addr, 138 | sizeof(stream->adrC.sin_addr.s_addr)); 139 | memcpy(&res.bndport, &stream->adrC.sin_port, 140 | sizeof(stream->adrC.sin_port));*/ 141 | break; 142 | 143 | case 0x02: 144 | /* In the reply to a BIND, two replies are sent from the SOCKS server 145 | * to the client during a BIND operation. */ 146 | if ( s->listen == 1 && s->connected == 0 ) { 147 | /* First replies 148 | * The BND.PORT field contains the port number that the 149 | * SOCKS server assigned to listen for an incoming connection. The 150 | * BND.ADDR field contains the associated IP address.*/ 151 | res.rep = 0x5a; 152 | /*memcpy(&res.bndaddr, &bind->adrC.sin_addr.s_addr, 153 | sizeof(bind->adrC.sin_addr.s_addr)); 154 | memcpy(&res.bndport, &bind->adrC.sin_port, 155 | sizeof(bind->adrC.sin_port));*/ 156 | } else if ( s->listen == 1 && s->connected == 1 ) { 157 | /* Second replies 158 | * The second reply occurs only after the anticipated incoming 159 | * connection succeeds or fails. In the second reply, 160 | * the BND.PORT and BND.ADDR fields contain the 161 | * address and port number of the connecting host.*/ 162 | res.rep = 0x5a; 163 | /*memcpy(&res.bndaddr, &stream->adrC.sin_addr.s_addr, 164 | sizeof(stream->adrC.sin_addr.s_addr)); 165 | memcpy(&res.bndport, &stream->adrC.sin_port, 166 | sizeof(stream->adrC.sin_port));*/ 167 | } else { 168 | res.rep = 0x5b; 169 | } 170 | 171 | 172 | break; 173 | 174 | default: 175 | res.rep = 0x01; 176 | break; 177 | } 178 | 179 | /* Copy in buffer for send */ 180 | memcpy(buf->data, &res, sizeof(Socks4ReqAck)); 181 | 182 | /* Reset counter and fix b flag */ 183 | buf->a = 0; 184 | buf->b = sizeof(Socks4ReqAck); 185 | } 186 | -------------------------------------------------------------------------------- /src/libsocks/socks4.h: -------------------------------------------------------------------------------- 1 | /* 2 | * socks4.h 3 | * 4 | * Created on: 2011-04-11 5 | * Author: Hugo Caron 6 | * Email: 7 | * 8 | * Copyright (C) 2011 by Hugo Caron 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | #ifndef SOCKS4__H 29 | #define SOCKS4__H 30 | 31 | #include "socks-common.h" 32 | #include "client.h" 33 | 34 | int test_request4(s_socks *s, s_socket *stream, s_socket *bind, 35 | s_socks_conf *c, s_buffer *buf); 36 | 37 | void build_request_ack4(s_socks *s, s_socks_conf *c, 38 | s_socket *stream, s_socket *bind, s_buffer *buf); 39 | 40 | #endif /* SOCKS5_SERVER__H */ 41 | 42 | -------------------------------------------------------------------------------- /src/libsocks/socks5-client.c: -------------------------------------------------------------------------------- 1 | /* 2 | * socks5-client.c 3 | * 4 | * Created on: 2011-04-11 5 | * Author: Hugo Caron 6 | * Email: 7 | * 8 | * Copyright (C) 2011 by Hugo Caron 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | 29 | #include "socks-common.h" 30 | #include "socks5-client.h" 31 | #include "socks5-server.h" 32 | #include "net-util.h" 33 | #include "bor-util.h" 34 | 35 | 36 | /* Build version packet in buf, 37 | * It get version and method from c param. 38 | * It copy Socks5Version struct in buf->data. 39 | * And set buf->a to zero and buf->b to sizeof(Socks5VersionACK) + nmethod 40 | * 41 | * From RFC1928: 42 | * The client connects to the server, and sends a version 43 | * identifier/method selection message: 44 | * 45 | * +----+----------+----------+ 46 | * |VER | NMETHODS | METHODS | 47 | * +----+----------+----------+ 48 | * | 1 | 1 | 1 to 255 | 49 | * +----+----------+----------+ 50 | */ 51 | void build_version(s_socks *s, s_socks_conf *c, s_buffer *buf) 52 | { 53 | Socks5Version req; 54 | 55 | init_buffer(buf); 56 | 57 | /* The VER field is set to X'05' for this version of the protocol. The 58 | * NMETHODS field contains the number of method identifier octets that 59 | * appear in the METHODS field. */ 60 | req.ver = c->config.cli->version; 61 | req.nmethods = c->config.cli->n_allowed_method; 62 | 63 | memcpy(buf->data, &req, 2); 64 | memcpy(buf->data+2, c->config.cli->allowed_method, req.nmethods); 65 | 66 | /* Reset counter and fix b flag */ 67 | buf->a = 0; 68 | buf->b = sizeof(Socks5VersionACK) + req.nmethods; 69 | } 70 | 71 | 72 | /* Test version packet ack in buf, 73 | * It check if version is same as start and save it in s->version 74 | * It check if method return by the server is supported and save it in s->method 75 | * Return: 76 | * -1, error wrong version 77 | * -2, error wrong method 78 | * 0, success 79 | * 80 | * From RFC1928: 81 | * The server selects from one of the methods given in METHODS, and 82 | * sends a METHOD selection message: 83 | * 84 | * +----+--------+ 85 | * |VER | METHOD | 86 | * +----+--------+ 87 | * | 1 | 1 | 88 | * +----+--------+ 89 | */ 90 | int test_version_ack(s_socks *s, s_socks_conf *c, s_buffer *buf) 91 | { 92 | Socks5VersionACK res; 93 | int j; 94 | TRACE(L_DEBUG, "client: testing version ack ..."); 95 | 96 | memcpy(&res, buf->data, sizeof(Socks5VersionACK)); 97 | 98 | /* Check the version */ 99 | if ( res.ver != c->config.cli->version ) { 100 | ERROR(L_NOTICE, "client: wrong socks version"); 101 | return -1; 102 | } 103 | s->version = res.ver; 104 | 105 | /* Check if method is allowed by the client */ 106 | for (j = 0; j < c->config.cli->n_allowed_method; ++j ) { 107 | if ( c->config.cli->allowed_method[j] == res.method ) { 108 | s->method = c->config.cli->allowed_method[j]; 109 | break; 110 | } 111 | } 112 | 113 | /* No valid method find */ 114 | if ( s->method == -1 ) { 115 | ERROR(L_VERBOSE, "client: method not supported", 116 | s->id); 117 | return -2; 118 | } 119 | 120 | return 0; 121 | } 122 | 123 | 124 | /* Build authentication packet in buf, 125 | * It set subnegotiation version to 0x01 126 | * It get uname/password from c->config.cli->username/password 127 | * It copy Socks5Auth struct in buf->data. 128 | * And set buf->a to zero and buf->b to 3 + req.ulen + req.plen 129 | * Return: 130 | * -1, error no username or password 131 | * 0, success 132 | * 133 | * From RFC1929: 134 | * Once the SOCKS V5 server has started, and the client has selected the 135 | * Username/Password Authentication protocol, the Username/Password 136 | * subnegotiation begins. This begins with the client producing a 137 | * Username/Password request: 138 | * 139 | * +----+------+----------+------+----------+ 140 | * |VER | ULEN | UNAME | PLEN | PASSWD | 141 | * +----+------+----------+------+----------+ 142 | * | 1 | 1 | 1 to 255 | 1 | 1 to 255 | 143 | * +----+------+----------+------+----------+ 144 | * 145 | * The VER field contains the current version of the subnegotiation, 146 | * which is X'01' 147 | */ 148 | int build_auth(s_socks *s, s_socks_conf *c, s_buffer *buf) 149 | { 150 | Socks5Auth req; 151 | char *uname, *passwd; 152 | 153 | init_buffer(buf); 154 | 155 | uname = c->config.cli->username; 156 | passwd = c->config.cli->password; 157 | 158 | if (uname == NULL || passwd == NULL) { 159 | ERROR(L_NOTICE, "client: need a login/password"); 160 | return -1; 161 | } 162 | 163 | /* Build authentication request */ 164 | req.ver = 0x01; /* subnegociation version (see RFC1929) */ 165 | req.ulen = (strlen(uname) < sizeof(req.uname)-1) ? 166 | strlen(uname) : sizeof(req.uname)-1; 167 | strcpy(req.uname, uname); 168 | req.plen = (strlen(passwd) < sizeof(req.passwd)-1) ? 169 | strlen(passwd) : sizeof(req.passwd)-1; 170 | strcpy(req.passwd, passwd); 171 | 172 | memcpy(buf->data, &req, 2); 173 | strcpy(&buf->data[2], req.uname); 174 | buf->data[2+req.ulen] = req.plen; 175 | strcpy(&buf->data[2+req.ulen+1], req.passwd); 176 | 177 | /* Reset counter and fix b flag */ 178 | buf->a = 0; 179 | buf->b = 3 + req.ulen + req.plen; 180 | 181 | return 0; 182 | } 183 | 184 | /* Test authentication packet ack in buf, 185 | * It check if subnegotiation version is 0x01 186 | * It check if authentication was success 187 | * Set s->auth = 1, means authentication was success 188 | * 189 | * Return: 190 | * -1, error server send wrong version number ( ver != 0x01 ) 191 | * -2, error authentication error (wrong username/password) 192 | * 0, success 193 | * 194 | * From RFC1929: 195 | * The server verifies the supplied UNAME and PASSWD, and sends the 196 | * following response: 197 | * 198 | * +----+--------+ 199 | * |VER | STATUS | 200 | * +----+--------+ 201 | * | 1 | 1 | 202 | * +----+--------+ 203 | * 204 | * The VER field contains the current version of the subnegotiation, 205 | * which is X'01' 206 | * 207 | * A STATUS field of X'00' indicates success. If the server returns a 208 | *`failure' (STATUS value other than X'00') status, it MUST close the 209 | * connection. 210 | */ 211 | int test_auth_ack(s_socks *s, s_socks_conf *c, s_buffer *buf) 212 | { 213 | Socks5AuthACK res; 214 | TRACE(L_DEBUG, "client: testing authentication ack ..."); 215 | 216 | memcpy(&res, buf->data, sizeof(Socks5VersionACK)); 217 | TRACE(L_DEBUG, "client: v0x%x, status 0x%02X", res.ver, res.status); 218 | 219 | /* Testing version of the subnegotiation need to be 0x01 */ 220 | if (res.ver != 0x01 ) { 221 | ERROR(L_NOTICE, "client: authentication need subnegotiation version 0x01"); 222 | return -1; 223 | } 224 | 225 | /* Testing status, if 0x00 indicates success */ 226 | if ( res.status != 0x00) { 227 | s->auth = 0; 228 | ERROR(L_NOTICE, "client: authentication error, " \ 229 | "maybe incorrect username/password"); 230 | return -2; 231 | } 232 | 233 | s->auth = 1; 234 | 235 | return 0; 236 | } 237 | 238 | /* Build request packet in buf, 239 | * It set version from s->version 240 | * It set cmd from c->config.cli->cmd (can be CMD_BIND, CMD_CONNECT, CMD_UDP) 241 | * It copy Socks5Req struct, followed by uname, plen and passwd in buf->data. 242 | * And set buf->a to zero and buf->b to sizeof(Socks5Req) + 1 + hostlen + 2 243 | * 244 | * From RFC1928: 245 | * The SOCKS request is formed as follows: 246 | * +----+-----+-------+------+----------+----------+ 247 | * |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | 248 | * +----+-----+-------+------+----------+----------+ 249 | * | 1 | 1 | X'00' | 1 | Variable | 2 | 250 | * +----+-----+-------+------+----------+----------+ 251 | * 252 | * Where: 253 | * o VER protocol version: X'05' 254 | * o CMD 255 | * o CONNECT X'01' ( define in CMD_CONNECT ) 256 | * o BIND X'02' ( define in CMD_BIND ) 257 | * o UDP ASSOCIATE X'03' ( define in CMD_UDP ) 258 | * o RSV RESERVED 259 | * o ATYP address type of following address 260 | * o IP V4 address: X'01' 261 | * o DOMAINNAME: X'03' 262 | * o IP V6 address: X'04' 263 | * o DST.ADDR desired destination address 264 | * o DST.PORT desired destination port in network octet 265 | * order 266 | * 267 | * TODO: client implement UDP support CMD_UDP 268 | * TODO: client implement ATYP with IPv4 269 | * TODO: client implement ATYP with IPv6 270 | */ 271 | void build_request(s_socks *s, s_socks_conf *c, s_buffer *buf) 272 | { 273 | Socks5Req req; 274 | init_buffer(buf); 275 | 276 | TRACE(L_DEBUG, "client: build request packet ..."); 277 | TRACE(L_DEBUG, "client: try to connect to %s:%d ...", 278 | c->config.cli->host, 279 | c->config.cli->port); 280 | 281 | /* Set the request */ 282 | req.ver = s->version; 283 | 284 | req.rsv = 0x00; 285 | req.atyp = 0x03; 286 | 287 | char *host; 288 | short port; 289 | 290 | req.cmd = s->cmd = c->config.cli->cmd; 291 | 292 | /* Command BIND */ 293 | if ( req.cmd == CMD_BIND ) { 294 | host = "0.0.0.0"; 295 | port = htons(c->config.cli->listen); 296 | } else if ( req.cmd == CMD_CONNECT ) { 297 | host = c->config.cli->host; 298 | port = htons(c->config.cli->port); 299 | } else { 300 | ERROR(L_VERBOSE, "client: configuration error, unknown command"); 301 | return; 302 | } 303 | 304 | /* Recover destination host and port form the config */ 305 | int hostlen = strlen(host); 306 | 307 | 308 | /* Copy the request in the req buffer */ 309 | memcpy(buf->data, &req, sizeof(Socks5Req)); 310 | buf->data[sizeof(Socks5Req)] = hostlen; 311 | strcpy(&buf->data[sizeof(Socks5Req) + 1], host); 312 | memcpy(&buf->data[sizeof(Socks5Req) + 1 + hostlen], &port, 2); 313 | 314 | /* Reset counter and fix b flag */ 315 | buf->a = 0; 316 | buf->b = sizeof(Socks5Req) + 1 + hostlen + 2; 317 | } 318 | 319 | 320 | /* Test request packet ack in buf 321 | * 322 | * Return: 323 | * -1, error, the request could not be completed 324 | * 0, success 325 | * 326 | * From RFC1928: 327 | * The server verifies the supplied UNAME and PASSWD, and sends the 328 | * following response: 329 | * 330 | * +----+-----+-------+------+----------+----------+ 331 | * |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | 332 | * +----+-----+-------+------+----------+----------+ 333 | * | 1 | 1 | X'00' | 1 | Variable | 2 | 334 | * +----+-----+-------+------+----------+----------+ 335 | * 336 | * Where: 337 | * o VER protocol version: X'05' 338 | * o REP Reply field: 339 | * o X'00' succeeded 340 | * o X'01' general SOCKS server failure 341 | * o X'02' connection not allowed by ruleset 342 | * o X'03' Network unreachable 343 | * o X'04' Host unreachable 344 | * o X'05' Connection refused 345 | * o X'06' TTL expired 346 | * o X'07' Command not supported 347 | * o X'08' Address type not supported 348 | * o X'09' to X'FF' unassigned 349 | * o RSV RESERVED (must be set to 0x00) 350 | * o ATYP address type of following address 351 | * o IP V4 address: X'01' 352 | * o DOMAINNAME: X'03' 353 | * o IP V6 address: X'04' 354 | * o BND.ADDR server bound address 355 | * o BND.PORT server bound port in network octet order 356 | * 357 | * TODO: Handle client request error 358 | */ 359 | int test_request_ack(s_socks *s, s_socks_conf *c, s_buffer *buf) 360 | { 361 | Socks5ReqACK res; 362 | 363 | TRACE(L_DEBUG, "client: testing request ack ..."); 364 | 365 | memcpy(&res, buf->data, sizeof(Socks5ReqACK)); 366 | 367 | TRACE(L_DEBUG, "client: v0x%x, rep 0x%x, rsv 0x%x, atyp 0x%x", 368 | res.ver, res.rep, res.rsv, res.atyp); 369 | 370 | 371 | if ( res.rep != 0x00) { 372 | ERROR(L_VERBOSE, "client: socks request ack error!"); 373 | ERROR(L_NOTICE, "client: error, destination is unavailable!"); 374 | return -1; 375 | } 376 | 377 | if ( c->config.cli->cmd == CMD_BIND ) { 378 | /* In the reply to a BIND, two replies are sent from the SOCKS server 379 | * to the client during a BIND operation. */ 380 | if ( s->listen == 0 ) { 381 | /* First replies 382 | * The BND.PORT field contains the port number that the 383 | * SOCKS server assigned to listen for an incoming connection. The 384 | * BND.ADDR field contains the associated IP address.*/ 385 | s->listen = 1; 386 | TRACE(L_VERBOSE, "client: listen on %s:%d", 387 | inet_ntoa(res.bndaddr), ntohs(res.bndport)); 388 | } else { 389 | /* Second replies 390 | * The second reply occurs only after the anticipated incoming 391 | * connection succeeds or fails. In the second reply, 392 | * the BND.PORT and BND.ADDR fields contain the 393 | * address and port number of the connecting host.*/ 394 | s->connected = 1; 395 | TRACE(L_DEBUG, "client: connection established with %s:%d", 396 | inet_ntoa(res.bndaddr), ntohs(res.bndport)); 397 | 398 | } 399 | } else { 400 | /* In the reply to a CONNECT, BND.PORT contains the port number that the 401 | * server assigned to connect to the target host, while BND.ADDR 402 | * contains the associated IP address. */ 403 | TRACE(L_VERBOSE, "client: pass through %s:%d", 404 | inet_ntoa(res.bndaddr), ntohs(res.bndport)); 405 | 406 | TRACE(L_DEBUG, "client: connection established"); 407 | 408 | s->connected = 1; 409 | } 410 | 411 | 412 | 413 | return 0; 414 | } 415 | 416 | /* Dispatch client write state, following socks5 RFC 417 | * In each state, it deal with write buf on soc and 418 | * change state to next 419 | * 420 | * Return: 421 | * -1, error something happen we need to disconnect the client 422 | * 0, success 423 | */ 424 | int dispatch_client_write(s_socket *soc, s_socks *socks, 425 | s_buffer *buf, s_socks_conf *conf) 426 | { 427 | int k = 0; 428 | switch(socks->state) { 429 | case S_W_VER: 430 | if ( buf_empty(buf) ) 431 | build_version(socks, conf, buf); 432 | 433 | WRITE_DISP(k, soc, buf); 434 | socks->state = S_R_VER_ACK; 435 | break; 436 | 437 | case S_W_AUTH: 438 | WRITE_DISP(k, soc, buf); 439 | socks->state = S_R_AUTH_ACK; 440 | break; 441 | 442 | case S_W_REQ: 443 | WRITE_DISP(k, soc, buf); 444 | socks->state = S_R_REQ_ACK; 445 | break; 446 | 447 | case S_REPLY: 448 | k = write_socks(soc, buf); 449 | if (k < 0) { 450 | close_socket(soc); /* Error */ 451 | break; 452 | } 453 | init_buffer(buf); 454 | break; 455 | 456 | default: 457 | break; 458 | } 459 | 460 | return k; 461 | } 462 | 463 | /* Dispatch client read state, following socks5 RFC 464 | * In each state, it deal with read in buf with soc, 465 | * test the packet with right function, build a reponse and 466 | * change state to next. 467 | * 468 | * Return: 469 | * -1, error something happen we need to disconnect the client 470 | * 0, success 471 | */ 472 | int dispatch_client_read(s_socket *soc, s_socket *soc_stream, 473 | s_socks *socks, s_buffer *buf, s_buffer *buf_stream, s_socks_conf *conf) 474 | { 475 | int k = 0; 476 | switch(socks->state) { 477 | case S_R_VER_ACK: 478 | READ_DISP(k, soc, buf, sizeof(Socks5VersionACK)); 479 | 480 | k = test_version_ack(socks, conf, buf); 481 | if (k < 0) { 482 | close_socket(soc); /* Error */ 483 | break; 484 | } 485 | 486 | /* It means need to send a authentication packet */ 487 | if ( socks->method == 0x02 ) { 488 | if ( build_auth(socks, conf, buf) < 0 ) { 489 | /* Something goes wrong, maybe no uname/passwd set in conf */ 490 | k = -1; 491 | break; 492 | } 493 | socks->state = S_W_AUTH; 494 | } else if ( socks->mode == M_DYNAMIC_CLIENT ) { 495 | /* In dynamic mode we do negociation with socks server and reply */ 496 | socks->state = S_REPLY; 497 | break; 498 | } else { 499 | build_request(socks, conf, buf); 500 | socks->state = S_W_REQ; 501 | } 502 | break; 503 | 504 | case S_R_AUTH_ACK: 505 | READ_DISP(k, soc, buf, sizeof(Socks5AuthACK)); 506 | 507 | k = test_auth_ack(socks, conf, buf); 508 | if (k < 0) { 509 | break; /* Error */ 510 | } 511 | 512 | if ( socks->mode == M_DYNAMIC_CLIENT ) { 513 | /* In dynamic mode we do negociation with socks server and reply */ 514 | socks->state = S_REPLY; 515 | break; 516 | } 517 | 518 | build_request(socks, conf, buf); 519 | socks->state = S_W_REQ; 520 | break; 521 | 522 | case S_R_REQ_ACK: 523 | READ_DISP(k, soc, buf, sizeof(Socks5ReqACK)); 524 | 525 | k = test_request_ack(socks, conf, buf); 526 | if (k < 0) { 527 | close_socket(soc); /* Error */ 528 | break; 529 | } 530 | 531 | if ( conf->config.cli->cmd == CMD_BIND ) { 532 | if ( socks->connected == 0 && socks->listen == 1) 533 | socks->state = S_R_REQ_ACK; 534 | else { 535 | socks->state = S_REPLY; 536 | /* End, stop client loop */ 537 | conf->config.cli->loop = 0; 538 | } 539 | } else { 540 | socks->state = S_REPLY; 541 | /* End, stop client loop */ 542 | conf->config.cli->loop = 0; 543 | } 544 | 545 | /* Clean buffer before enter in reply mode */ 546 | init_buffer(buf); 547 | break; 548 | 549 | case S_REPLY: 550 | if ( buf_free(buf_stream) > 0 ) { 551 | k = read_socks(soc, buf_stream, 0); 552 | if (k < 0) { 553 | close_socket(soc); /* Error */ 554 | break; 555 | } 556 | } 557 | break; 558 | 559 | default: 560 | break; 561 | } 562 | return k; 563 | } 564 | 565 | /* Dispatch client, it's normally called after a select 566 | * Search client with socket in set_read and set_write and call 567 | * the right dispatcher. 568 | * 569 | * It's responsible for disconnecting the client 570 | * in case of protocol error or network error. 571 | */ 572 | void dispatch_client(s_client *client, fd_set *set_read, fd_set *set_write) 573 | { 574 | int k = 0; 575 | 576 | /* Dispatch server socket */ 577 | if (client->soc.soc != -1 && FD_ISSET (client->soc.soc, set_read)) 578 | k = dispatch_client_read(&client->soc, &client->soc_stream, 579 | &client->socks, &client->buf, &client->stream_buf, client->conf); 580 | else if (client->soc.soc != -1 && 581 | FD_ISSET (client->soc.soc, set_write)) 582 | k = dispatch_client_write(&client->soc, &client->socks, &client->buf, client->conf); 583 | 584 | /* Error client disconnection */ 585 | if (k < 0) { 586 | disconnection(client); 587 | } 588 | } 589 | 590 | /* Dispatch client dynamic, it's normally called after a select 591 | * Based on dispatch_server function 592 | * 593 | * It's responsible for disconnecting the client 594 | * in case of protocol error or network error. 595 | */ 596 | void dispatch_dynamic(s_client *client, fd_set *set_read, fd_set *set_write) 597 | { 598 | int k = 0; 599 | /* Dispatch server socket */ 600 | if (client->soc.soc != -1 && FD_ISSET (client->soc.soc, set_read)) 601 | k = dispatch_server_read(&client->soc, &client->soc_stream, &client->soc_bind, 602 | &client->socks, &client->buf, &client->stream_buf, client->conf); 603 | 604 | else if (client->soc.soc != -1 && 605 | FD_ISSET (client->soc.soc, set_write)) 606 | k = dispatch_server_write(&client->soc, &client->soc_stream, &client->socks, &client->buf, client->conf); 607 | if (k < 0) { 608 | disconnection(client); 609 | return; 610 | } 611 | 612 | /* Dispatch stream socket */ 613 | if (client->soc_stream.soc != -1 && FD_ISSET (client->soc_stream.soc, set_read)) 614 | k = dispatch_client_read(&client->soc_stream, &client->soc, 615 | &client->socks_stream, &client->stream_buf, &client->buf, client->conf); 616 | else if (client->soc_stream.soc != -1 && 617 | FD_ISSET (client->soc_stream.soc, set_write)) 618 | k = dispatch_client_write(&client->soc_stream, &client->socks_stream, &client->stream_buf, client->conf); 619 | if (k < 0) { 620 | disconnection(client); 621 | return; 622 | } 623 | 624 | /* Dispatch bind socket (it's server socket)*/ 625 | if (client->soc_bind.soc != -1 && 626 | FD_ISSET (client->soc_bind.soc, set_read)) { 627 | if ( build_request_accept_bind(&client->socks, client->conf, 628 | &client->soc, &client->soc_bind, &client->stream_buf) == 0 ) { 629 | client->socks.state = S_W_REQ_ACK; 630 | } 631 | } 632 | 633 | } 634 | 635 | /* Prepare set_read and set_write for a select with a client connection (nsocks) 636 | * Initialize set_read and set_write with right socket in function of socks state 637 | * It's responsible to set maxfd to max soc->soc value in set_read or set_write 638 | */ 639 | void init_select_client (s_socket *soc, s_socks *s, s_buffer *buf, int *maxfd, 640 | fd_set *set_read, fd_set *set_write) 641 | { 642 | if ( soc->soc != -1 ) { 643 | if ( s->state == S_R_VER_ACK || 644 | s->state == S_R_AUTH_ACK || 645 | s->state == S_R_REQ_ACK ) 646 | { 647 | FD_SET(soc->soc, set_read); 648 | } else if (s->state == S_W_VER || 649 | s->state == S_W_AUTH || 650 | s->state == S_W_REQ) 651 | { 652 | FD_SET(soc->soc, set_write); 653 | } else if ( s->state == S_REPLY ) { 654 | if ( buf_empty(buf) == 0 ) { 655 | FD_SET(soc->soc, set_write); 656 | } else { 657 | FD_SET(soc->soc, set_read); 658 | } 659 | } 660 | 661 | if (soc->soc > *maxfd) *maxfd = soc->soc; 662 | } 663 | } 664 | 665 | /* Prepare set_read and set_write for a select with a dynamic connection (ssocks) 666 | * Initialize set_read and set_write with right socket in function of socks state 667 | * It's responsible to set maxfd to max soc->soc value in set_read or set_write 668 | */ 669 | void init_select_dynamic (int soc_ec, s_client *tc, int *maxfd, 670 | fd_set *set_read, fd_set *set_write) 671 | { 672 | int nc; 673 | 674 | FD_ZERO (set_read); 675 | FD_ZERO (set_write); 676 | FD_SET (soc_ec, set_read); 677 | 678 | *maxfd = soc_ec; 679 | for (nc = 0; nc < MAXCLI; nc++) { 680 | s_client *client = &tc[nc]; 681 | 682 | if (client->socks_stream.state == S_REPLY 683 | && client->socks.state == S_WAIT) 684 | { 685 | client->socks.state = S_REPLY; 686 | memcpy(&client->stream_buf, &client->buf, sizeof(s_buffer)); 687 | init_buffer(&client->buf); 688 | } 689 | 690 | init_select_server_cli(&client->soc, &client->socks, &client->buf, 691 | &client->stream_buf, maxfd, set_read, set_write); 692 | 693 | init_select_client(&client->soc_stream, &client->socks_stream, 694 | &client->stream_buf, 695 | maxfd, set_read, set_write); 696 | 697 | 698 | if ( client->soc_bind.soc != -1 ) { 699 | FD_SET(client->soc_bind.soc, set_read); 700 | if (client->soc_bind.soc > *maxfd) *maxfd = client->soc_bind.soc; 701 | } 702 | } 703 | } 704 | 705 | /* Create a connection to a host trough a socks5 706 | * If success s contain a socket to server 707 | * 708 | * If listen port != 0, it means bind mode, 709 | * so host and port will be ignored 710 | * 711 | * Return: 712 | * -1, connection error, unavailable socks server 713 | * 0, connection error, socks5 negociation 714 | * 1, connection establish, socket is set in struct s 715 | */ 716 | int new_socket_with_socks(s_socket *s, 717 | char *sockshost, int socksport, 718 | char *username, char *password, 719 | char *host, int port, int listen, 720 | int version, int ssl, int cmd) 721 | { 722 | int maxfd = 0, res; 723 | fd_set set_read, set_write; 724 | 725 | s_socks_conf conf; 726 | s_socks_client_config config; 727 | conf.config.cli = &config; 728 | 729 | char method[] = { 0x00, 0x02 }; 730 | conf.config.cli->n_allowed_method = 2; 731 | conf.config.cli->allowed_method = method; 732 | 733 | /* If no username or password we don't use auth */ 734 | if ( username == NULL || password == NULL ) 735 | --conf.config.cli->n_allowed_method; 736 | 737 | conf.config.cli->loop = 1; 738 | conf.config.cli->cmd = cmd; 739 | conf.config.cli->host = host; 740 | conf.config.cli->port = port; 741 | conf.config.cli->listen = listen; 742 | conf.config.cli->version = version; 743 | conf.config.cli->username = username; 744 | conf.config.cli->password = password; 745 | 746 | //memcpy(&conf.config, &config, sizeof(s_socks_serv_cli_config)); 747 | 748 | s_client c; 749 | init_client (&c, 0, M_CLIENT, &conf); 750 | 751 | c.soc.soc = new_client_socket(sockshost, socksport, 752 | &c.soc.adrC, &c.soc.adrS); 753 | if ( c.soc.soc < 0 ) { 754 | return -1; 755 | } 756 | 757 | #ifdef HAVE_LIBSSL 758 | /* Init SSL here 759 | */ 760 | if (ssl == 1) { 761 | TRACE(L_DEBUG, "client: socks5 enable ssl ..."); 762 | c.soc.ssl = ssl_neogiciate_client(c.soc.soc); 763 | if ( c.soc.ssl == NULL ) { 764 | ERROR(L_VERBOSE, "client: ssl error"); 765 | return -3; 766 | } 767 | TRACE(L_DEBUG, "client: ssl ok."); 768 | } 769 | #endif /* HAVE_LIBSSL */ 770 | 771 | /* Select loop */ 772 | while (conf.config.cli->loop == 1 && c.soc.soc != -1) { 773 | 774 | FD_ZERO (&set_read); 775 | FD_ZERO (&set_write); 776 | maxfd = 0; 777 | 778 | /* Adds the socket in read fds */ 779 | init_select_client(&c.soc, &c.socks, &c.buf, &maxfd, &set_read, &set_write); 780 | 781 | res = select (maxfd+1, &set_read, &set_write, NULL, NULL); 782 | if (res > 0) { 783 | dispatch_client(&c, &set_read, &set_write); 784 | } else if ( res == 0) { 785 | 786 | } else if (res < 0) { 787 | if (errno == EINTR) ; /* Received signal, it does nothing */ 788 | else { 789 | perror ("select"); 790 | disconnection(&c); 791 | return -1; 792 | } 793 | } 794 | } 795 | 796 | memcpy(s, &c.soc, sizeof(s_socket)); 797 | return (c.soc.soc >= 0); 798 | } 799 | -------------------------------------------------------------------------------- /src/libsocks/socks5-client.h: -------------------------------------------------------------------------------- 1 | /* 2 | * socks5-client.h 3 | * 4 | * Created on: 2011-04-11 5 | * Author: Hugo Caron 6 | * Email: 7 | * 8 | * Copyright (C) 2011 by Hugo Caron 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | #include "socks-common.h" 29 | #include "client.h" 30 | 31 | void build_version(s_socks *s, s_socks_conf *c, s_buffer *buf); 32 | int test_version_ack(s_socks *s, s_socks_conf *c, s_buffer *buf); 33 | 34 | int build_auth(s_socks *s, s_socks_conf *c, s_buffer *buf); 35 | int test_auth_ack(s_socks *s, s_socks_conf *c, s_buffer *buf); 36 | 37 | void build_request(s_socks *s, s_socks_conf *c, s_buffer *buf); 38 | int test_request_ack(s_socks *s, s_socks_conf *c, s_buffer *buf); 39 | 40 | 41 | int dispatch_client_write(s_socket *soc, s_socks *socks, 42 | s_buffer *buf, s_socks_conf *conf); 43 | int dispatch_client_read(s_socket *soc, s_socket *soc_stream, 44 | s_socks *socks, s_buffer *buf, s_buffer *buf_stream, s_socks_conf *conf); 45 | 46 | void dispatch_client(s_client *client, fd_set *set_read, fd_set *set_write); 47 | 48 | void dispatch_dynamic(s_client *client, fd_set *set_read, fd_set *set_write); 49 | 50 | void init_select_client (s_socket *soc, s_socks *s, s_buffer *buf, int *maxfd, 51 | fd_set *set_read, fd_set *set_write); 52 | 53 | void init_select_dynamic (int soc_ec, s_client *tc, int *maxfd, 54 | fd_set *set_read, fd_set *set_write); 55 | 56 | int new_socket_with_socks(s_socket *s, 57 | char *sockshost, int socksport, 58 | char *username, char *password, 59 | char *host, int port, int listen, 60 | int version, int ssl, int cmd); 61 | -------------------------------------------------------------------------------- /src/libsocks/socks5-server.c: -------------------------------------------------------------------------------- 1 | /* 2 | * socks5-server.c 3 | * 4 | * Created on: 2011-04-11 5 | * Author: Hugo Caron 6 | * Email: 7 | * 8 | * Copyright (C) 2011 by Hugo Caron 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | 29 | #include "socks4.h" 30 | #include "socks-common.h" 31 | #include "socks5-server.h" 32 | #include "net-util.h" 33 | #include "log-util.h" 34 | 35 | 36 | #include "bor-util.h" 37 | 38 | #include 39 | 40 | 41 | /* Test version packet in buf, 42 | * It check if version is allowed in c->config.srv->allowed_version 43 | * and save it in s->version 44 | * It check if version is allowed in c->config.srv->allowed_methods 45 | * and save it in s->method 46 | * 47 | * Return: 48 | * -1, error wrong version 49 | * -2, error wrong method 50 | * 0, success 51 | * 52 | * From RFC1928: 53 | * The client connects to the server, and sends a version 54 | * identifier/method selection message: 55 | * 56 | * +----+----------+----------+ 57 | * |VER | NMETHODS | METHODS | 58 | * +----+----------+----------+ 59 | * | 1 | 1 | 1 to 255 | 60 | * +----+----------+----------+ 61 | * 62 | * The values currently defined for METHOD are: 63 | * o X'00' NO AUTHENTICATION REQUIRED (supported) 64 | * o X'01' GSSAPI 65 | * o X'02' USERNAME/PASSWORD (supported) 66 | * o X'03' to X'7F' IANA ASSIGNED 67 | * o X'80' to X'FE' RESERVED FOR PRIVATE METHODS 68 | * o X'FF' NO ACCEPTABLE METHODS 69 | */ 70 | int test_version(s_socks *s, s_socks_conf *c, s_buffer *buf) { 71 | int i, j; 72 | Socks5Version req; 73 | TRACE(L_DEBUG, "server [%d]: testing version ...", 74 | s->id); 75 | 76 | memcpy(&req, buf->data, sizeof(Socks5Version)); 77 | 78 | /* Testing version */ 79 | char *allowed; 80 | for (i=0; i < c->config.srv->n_allowed_version; ++i) { 81 | allowed = &c->config.srv->allowed_version[i]; 82 | if ( *allowed == req.ver ) { 83 | s->version = *allowed; 84 | TRACE(L_DEBUG, "server [%d]: version %d", 85 | s->id, s->version); 86 | break; 87 | } 88 | } 89 | 90 | /* No valid version find */ 91 | if ( s->version == -1 ) { 92 | ERROR(L_VERBOSE, "server [%d]: version error (%d)", 93 | s->id, req.ver); 94 | return -1; 95 | } 96 | 97 | if ( s->version == SOCKS4_V) { 98 | return 0; 99 | } 100 | 101 | /* If too much method we truncate */ 102 | if (sizeof(req.methods) < (unsigned int)req.nmethods) { 103 | ERROR(L_VERBOSE, "server [%d]: truncate methods", 104 | s->id); 105 | req.nmethods = sizeof(req.methods); 106 | } 107 | 108 | /* Show only in debug mode */ 109 | if ( L_DEBUG <= verbosity ) { 110 | printf("server [%d]: methods ", s->id); 111 | } 112 | 113 | /* Copy in methods the methods in the packet 114 | * memcpy can do the trick too */ 115 | for (i=0; i < req.nmethods; ++i) { 116 | req.methods[i] = *(buf->data + 2 + i ); 117 | /* Show only in debug mode */ 118 | if ( L_DEBUG <= verbosity ) { 119 | printf("0x%02X,",req.methods[i]); 120 | } 121 | } 122 | 123 | /* Show only in debug mode */ 124 | if ( L_DEBUG <= verbosity ) { 125 | printf("\n"); 126 | } 127 | 128 | /* Searching valid methods: 129 | * Methods 0x00, no authentication 130 | * 0x01, GSSAPI no supported 131 | * 0x02, username/password RFC1929 132 | */ 133 | for (i=0; i < req.nmethods && s->method == -1; ++i) { 134 | for (j = 0; j < c->config.srv->n_allowed_method; ++j ) { 135 | if ( c->config.srv->allowed_method[j] == req.methods[i] ) { 136 | s->method = c->config.srv->allowed_method[j]; 137 | break; 138 | } 139 | } 140 | } 141 | 142 | /* No valid method find */ 143 | if ( s->method == -1 ) { 144 | ERROR(L_VERBOSE, "server [%d]: method not supported", 145 | s->id); 146 | return -2; 147 | } 148 | 149 | return 0; 150 | } 151 | 152 | /* Build version packet ack in buf 153 | * 154 | * From RFC1928: 155 | * The server selects from one of the methods given in METHODS, and 156 | * sends a METHOD selection message: 157 | * 158 | * +----+--------+ 159 | * |VER | METHOD | 160 | * +----+--------+ 161 | * | 1 | 1 | 162 | * +----+--------+ 163 | */ 164 | void build_version_ack(s_socks *s, s_socks_conf *c, s_buffer *buf) 165 | { 166 | Socks5VersionACK res; 167 | init_buffer(buf); 168 | res.ver = s->version; 169 | res.method = s->method; 170 | 171 | /* Copy in buffer for send */ 172 | memcpy(buf->data, &res, sizeof(Socks5VersionACK)); 173 | 174 | /* Reset counter and fix b flag */ 175 | buf->a = 0; 176 | buf->b = sizeof(Socks5VersionACK); 177 | } 178 | 179 | /* Analyse authentication packet and check uname/password 180 | * It set s->auth to 0 if authentication failed and to 1 if success 181 | * 182 | * Return: 183 | * -1 error, wrong subnegotiation version 184 | * 0 success 185 | * From RFC1929: 186 | * Once the SOCKS V5 server has started, and the client has selected the 187 | * Username/Password Authentication protocol, the Username/Password 188 | * subnegotiation begins. This begins with the client producing a 189 | * Username/Password request: 190 | * 191 | * +----+------+----------+------+----------+ 192 | * |VER | ULEN | UNAME | PLEN | PASSWD | 193 | * +----+------+----------+------+----------+ 194 | * | 1 | 1 | 1 to 255 | 1 | 1 to 255 | 195 | * +----+------+----------+------+----------+ 196 | * 197 | * The VER field contains the current version of the subnegotiation, 198 | * which is X'01' 199 | */ 200 | int test_auth(s_socks *s, s_socks_conf *c, s_buffer *buf) 201 | { 202 | Socks5Auth req; 203 | 204 | TRACE(L_DEBUG, "server [%d]: testing authentication ...", 205 | s->id); 206 | 207 | /* Rebuild the packet in Socks5Auth struct */ 208 | memcpy(&req, buf->data, 2); 209 | memcpy(&req.plen, buf->data + 2 + (int)req.ulen , 2); 210 | 211 | /* Check username and password length truncate if too long 212 | * RFC tell us max length 255 */ 213 | if ( (unsigned int)req.ulen > sizeof(req.uname)-1) { 214 | ERROR(L_NOTICE, "server [%d]: username too long", 215 | s->id); 216 | req.ulen = sizeof(req.uname)-1; 217 | 218 | ERROR(L_VERBOSE, "server [%d]: authentication NOK!", 219 | s->id); 220 | s->auth = 0; 221 | 222 | return 0; 223 | } 224 | if ( (unsigned int)req.plen > sizeof(req.passwd)-1) { 225 | ERROR(L_NOTICE, "server [%d]: password too long", 226 | s->id); 227 | req.plen = sizeof(req.passwd)-1; 228 | 229 | ERROR(L_VERBOSE, "server [%d]: authentication NOK!", 230 | s->id); 231 | s->auth = 0; 232 | 233 | return 0; 234 | } 235 | 236 | /* Extract username and fix NULL byte */ 237 | strncpy(req.uname, buf->data + 2, req.ulen); 238 | *(req.uname + req.ulen) = '\0'; 239 | 240 | /* Extract passwd and fix NULL byte */ 241 | strncpy(req.passwd, buf->data + 2 + (int)req.ulen + 1, req.plen); 242 | *(req.passwd + req.plen) = '\0'; 243 | //DUMP(buf->data, buf->b); 244 | TRACE(L_VERBOSE, "server [%d]: authentication attempt "\ 245 | "v0x%02X (%d,%d) %s:%s", 246 | s->id, 247 | req.ver, req.ulen, req.plen, req.uname, req.passwd); 248 | 249 | /* Test version need 0x01 RFC */ 250 | if ( req.ver != 0x01 ) { 251 | ERROR(L_NOTICE, "server [%d]: wrong subnegotiation version need to be 0x01", 252 | s->id); 253 | return -1; 254 | } 255 | 256 | /* Check username and password in authentication file */ 257 | if ( c->config.srv->check_auth == NULL ) { 258 | ERROR(L_NOTICE, "server [%d]: wrong configuration no check_auth callback set", 259 | s->id); 260 | return -2; 261 | } 262 | if ( (*c->config.srv->check_auth)(req.uname, req.passwd) == 1 ) { 263 | TRACE(L_VERBOSE, "server [%d]: authentication OK!", 264 | s->id); 265 | strcpy(s->uname, req.uname); 266 | s->auth = 1; 267 | } else { 268 | ERROR(L_VERBOSE, "server [%d]: authentication NOK!", 269 | s->id); 270 | s->auth = 0; 271 | } 272 | 273 | return 0; 274 | } 275 | 276 | /* Build authentication packet ack in buf 277 | * Check s->auth to set status field 278 | * 279 | * From RFC1929: 280 | * The server verifies the supplied UNAME and PASSWD, and sends the 281 | * following response: 282 | * 283 | * +----+--------+ 284 | * |VER | STATUS | 285 | * +----+--------+ 286 | * | 1 | 1 | 287 | * +----+--------+ 288 | * 289 | * The VER field contains the current version of the subnegotiation, 290 | * which is X'01' 291 | * 292 | * A STATUS field of X'00' indicates success. If the server returns a 293 | *`failure' (STATUS value other than X'00') status, it MUST close the 294 | * connection. 295 | */ 296 | void build_auth_ack(s_socks *s, s_socks_conf *c, s_buffer *buf) 297 | { 298 | Socks5AuthACK res; 299 | init_buffer(buf); 300 | res.ver = 0x01; 301 | res.status = (s->auth) ? 0x00 : 0xFF; /* 0x00 == win! */ 302 | 303 | /* Copy in buffer for send */ 304 | memcpy(buf->data, &res, sizeof(Socks5VersionACK)); 305 | 306 | /* Reset counter and fix b flag */ 307 | buf->a = 0; 308 | buf->b = sizeof(Socks5VersionACK); 309 | } 310 | 311 | /* Test request packet in buf, and execute the request 312 | * 313 | * Return: 314 | * -EINVAL, invalid argument (typ, cmd, udp) 315 | * -EAGAIN, expects more bytes in buffer 316 | * -1, other error 317 | * 0, success 318 | * 319 | * From RFC1928: 320 | * The SOCKS request is formed as follows: 321 | * +----+-----+-------+------+----------+----------+ 322 | * |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | 323 | * +----+-----+-------+------+----------+----------+ 324 | * | 1 | 1 | X'00' | 1 | Variable | 2 | 325 | * +----+-----+-------+------+----------+----------+ 326 | * 327 | * Where: 328 | * o VER protocol version: X'05' 329 | * o CMD 330 | * o CONNECT X'01' ( define in CMD_CONNECT ) 331 | * o BIND X'02' ( define in CMD_BIND ) 332 | * o UDP ASSOCIATE X'03' ( define in CMD_UDP ) 333 | * o RSV RESERVED 334 | * o ATYP address type of following address 335 | * o IP V4 address: X'01' 336 | * o DOMAINNAME: X'03' 337 | * o IP V6 address: X'04' 338 | * o DST.ADDR desired destination address 339 | * o DST.PORT desired destination port in network octet 340 | * order 341 | * 342 | * TODO: server implement UDP support CMD_UDP 343 | * TODO: server implement ATYP with IPv6 344 | */ 345 | int analyse_request(s_socks *s, s_socket *stream, s_socket *bind, 346 | s_socks_conf *c, s_buffer *buf) 347 | { 348 | Socks5Req req; 349 | TRACE(L_DEBUG, "server [%d]: testing client request ...", 350 | s->id); 351 | 352 | uint16_t port = 0, *p; 353 | char domain[256]; 354 | char chAddr[4]; 355 | uint8_t l; 356 | struct in_addr addr; 357 | /* Rebuild the packet but don't extract 358 | * DST.ADDR and DST.PORT in Socks5Req struct */ 359 | memcpy(&req, buf->data, sizeof(Socks5Req)); 360 | TRACE(L_DEBUG, "server [%d]: v0x%x, cmd 0x%x, rsv 0x%x, atyp 0x%x", 361 | s->id, req.ver, 362 | req.cmd, req.rsv, req.atyp); 363 | 364 | /* Save the request cmd */ 365 | s->cmd = req.cmd; 366 | 367 | /* Check ATYP 368 | * ATYP address type of following address 369 | * - IP V4 address: X'01' 370 | * - DOMAINNAME: X'03' 371 | * - IP V6 address: X'04' 372 | */ 373 | switch ( req.atyp ) { 374 | case 0x03: /* Domain name */ 375 | 376 | if (!PEEK_DISP(buf, sizeof(Socks5Req) + 1)) return -EAGAIN; 377 | 378 | /* First byte is the domain len */ 379 | l = *(buf->data + sizeof(Socks5Req)); 380 | 381 | /* 1 addrlen + l domain + 2 port */ 382 | if (!PEEK_DISP(buf, sizeof(Socks5Req) + 1 + l + 2)) return -EAGAIN; 383 | 384 | /* Copy the domain name and blank at end 385 | * little cheat to avoid overflow (dangerous here) */ 386 | memcpy(domain, buf->data + sizeof(Socks5Req) + 1, l); 387 | domain[(int)l] = '\0'; 388 | 389 | /* After domain we have the port 390 | * big endian on 2 bytes*/ 391 | p = (uint16_t*)(buf->data + sizeof(Socks5Req) + l + 1) ; 392 | port = ntohs(*p); 393 | 394 | TRACE(L_DEBUG, "Server [%d]: asking for %s:%d", s->id, domain, port); 395 | break; 396 | 397 | case 0x01: /* IP address */ 398 | 399 | if (!PEEK_DISP(buf, sizeof(Socks5Req) + sizeof(chAddr) + 2)) return -EAGAIN; 400 | 401 | memcpy(&chAddr, (buf->data + sizeof(Socks5Req)), sizeof(chAddr)); 402 | inet_pton(AF_INET, chAddr, &addr); 403 | 404 | /* After domain we have the port 405 | * big endian on 2 bytes*/ 406 | p = (uint16_t*)(buf->data + sizeof(Socks5Req) + 4 ) ; 407 | port = ntohs(*p); 408 | break; 409 | 410 | /* TODO: ipv6 support */ 411 | default: 412 | ERROR(L_NOTICE, "server [%d]: support domain name "\ 413 | "and ipv4 only", 414 | s->id); 415 | return -EINVAL; 416 | } 417 | 418 | 419 | 420 | /* CMD: 421 | * - CONNECT X'01' 422 | * - BIND X'02' 423 | * - UDP ASSOCIATE X'03' 424 | * 425 | * Open or bind connection here 426 | */ 427 | switch(req.cmd) { 428 | case 0x01: /* TCP/IP Stream connection */ 429 | if ( req.atyp == 0x01 ) 430 | stream->soc = new_client_socket_no_ip(chAddr, port, &stream->adrC, &stream->adrS); 431 | else 432 | stream->soc = new_client_socket_no(domain, port, &stream->adrC, &stream->adrS); 433 | if ( stream->soc < 0 ) { 434 | return -1; 435 | } 436 | break; 437 | case 0x02: /* TCP/IP port binding */ 438 | bind->soc = new_listen_socket(NULL, port, 10, &bind->adrC); 439 | if ( bind->soc >= 0 ) { 440 | s->connected = 0; 441 | s->listen = 1; 442 | 443 | } 444 | 445 | break; 446 | /* TODO: udp support */ 447 | default : 448 | ERROR(L_NOTICE, "server [%d]: doesn't support udp", 449 | s->id); 450 | return -EINVAL; 451 | } 452 | 453 | return 0; 454 | } 455 | 456 | int test_request_dynamic(s_socks *s, s_socks_conf *c, s_buffer *buf) 457 | { 458 | return -1; 459 | } 460 | 461 | /* Build request packet ack in buf 462 | * 463 | * From RFC1928: 464 | * The server verifies the supplied UNAME and PASSWD, and sends the 465 | * following response: 466 | * +----+-----+-------+------+----------+----------+ 467 | * |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | 468 | * +----+-----+-------+------+----------+----------+ 469 | * | 1 | 1 | X'00' | 1 | Variable | 2 | 470 | * +----+-----+-------+------+----------+----------+ 471 | * 472 | * Where: 473 | * o VER protocol version: X'05' 474 | * o REP Reply field: 475 | * o X'00' succeeded 476 | * o X'01' general SOCKS server failure 477 | * o X'02' connection not allowed by ruleset 478 | * o X'03' Network unreachable 479 | * o X'04' Host unreachable 480 | * o X'05' Connection refused 481 | * o X'06' TTL expired 482 | * o X'07' Command not supported 483 | * o X'08' Address type not supported 484 | * o X'09' to X'FF' unassigned 485 | * o RSV RESERVED (must be set to 0x00) 486 | * o ATYP address type of following address 487 | * o IP V4 address: X'01' 488 | * o DOMAINNAME: X'03' 489 | * o IP V6 address: X'04' 490 | * o BND.ADDR server bound address 491 | * o BND.PORT server bound port in network octet order 492 | * 493 | * TODO: Handle server request error, in case of fails send 0X01 494 | */ 495 | void build_request_ack(s_socks *s, s_socks_conf *c, 496 | s_socket *stream, s_socket *bind, s_buffer *buf) 497 | { 498 | 499 | Socks5ReqACK res; 500 | int k; 501 | 502 | socklen_t socklen = sizeof(int); 503 | res.ver = s->version; 504 | res.rsv = 0; 505 | res.atyp = 0x01; 506 | 507 | init_buffer(buf); 508 | 509 | switch(s->cmd) { 510 | case 0x01: 511 | /* 0x00 succeeded, 0x01 general SOCKS failure ... */ 512 | 513 | if ( getsockopt(stream->soc, SOL_SOCKET, SO_ERROR, &k, &socklen) < 0) { 514 | perror("getsockopt"); 515 | close_socket(stream); 516 | s->connected = 0; 517 | res.rep = 0x01; 518 | break; 519 | } 520 | 521 | if (k != 0) { 522 | ERROR(L_VERBOSE, "client: error %d", k); 523 | close_socket(stream); 524 | s->connected = 0; 525 | res.rep = 0x01; 526 | break; 527 | } 528 | 529 | /* Recovering the client address and port after the connection*/ 530 | if ( bor_getsockname_in(stream->soc, &stream->adrC) < 0 ) { 531 | close_socket(stream); 532 | s->connected = 0; 533 | res.rep = 0x01; 534 | break; 535 | } 536 | 537 | /* In the reply to a CONNECT, BND.PORT contains 538 | * the port number that the server assigned to 539 | * connect to the target host, while BND.ADDR 540 | * contains the associated IP address. */ 541 | res.rep = 0x00; 542 | s->connected = 1; 543 | memcpy(&res.bndaddr, &stream->adrC.sin_addr.s_addr, 544 | sizeof(stream->adrC.sin_addr.s_addr)); 545 | memcpy(&res.bndport, &stream->adrC.sin_port, 546 | sizeof(stream->adrC.sin_port)); 547 | break; 548 | 549 | case 0x02: 550 | /* In the reply to a BIND, two replies are sent from the SOCKS server 551 | * to the client during a BIND operation. */ 552 | if ( s->listen == 1 && s->connected == 0 ) { 553 | /* First replies 554 | * The BND.PORT field contains the port number that the 555 | * SOCKS server assigned to listen for an incoming connection. The 556 | * BND.ADDR field contains the associated IP address.*/ 557 | res.rep = 0x00; 558 | memcpy(&res.bndaddr, &bind->adrC.sin_addr.s_addr, 559 | sizeof(bind->adrC.sin_addr.s_addr)); 560 | memcpy(&res.bndport, &bind->adrC.sin_port, 561 | sizeof(bind->adrC.sin_port)); 562 | } else if ( s->listen == 1 && s->connected == 1 ) { 563 | /* Second replies 564 | * The second reply occurs only after the anticipated incoming 565 | * connection succeeds or fails. In the second reply, 566 | * the BND.PORT and BND.ADDR fields contain the 567 | * address and port number of the connecting host.*/ 568 | res.rep = 0x00; 569 | memcpy(&res.bndaddr, &stream->adrC.sin_addr.s_addr, 570 | sizeof(stream->adrC.sin_addr.s_addr)); 571 | memcpy(&res.bndport, &stream->adrC.sin_port, 572 | sizeof(stream->adrC.sin_port)); 573 | } else { 574 | res.rep = 0x01; 575 | } 576 | 577 | 578 | break; 579 | 580 | default: 581 | res.rep = 0x01; 582 | break; 583 | } 584 | 585 | /* Copy in buffer for send */ 586 | memcpy(buf->data, &res, sizeof(Socks5ReqACK)); 587 | 588 | /* Reset counter and fix b flag */ 589 | buf->a = 0; 590 | buf->b = sizeof(Socks5ReqACK); 591 | } 592 | 593 | /* Build request accept bind packet in buf 594 | * It's accept a connection on the socket bind 595 | * and associate with socket stream 596 | * 597 | * Return: 598 | * -1 error, accept error socket problem 599 | * 0 success 600 | * 601 | */ 602 | int build_request_accept_bind(s_socks *s, s_socks_conf *c, 603 | s_socket *stream, s_socket *bind, s_buffer *buf) 604 | { 605 | init_buffer(buf); 606 | 607 | TRACE(L_VERBOSE, "server [%d]: build binding packet ...", 608 | s->id); 609 | 610 | stream->soc = bor_accept_in (bind->soc, &stream->adrC); 611 | if ( stream->soc < 0 ) { 612 | s->connected = -1; /* Send a error request ack */ 613 | return -1; 614 | } 615 | 616 | s->connected = 1; 617 | 618 | TRACE(L_DEBUG, "server: established connection with %s", 619 | bor_adrtoa_in(&stream->adrC)); 620 | 621 | build_request_ack(s, c, stream, bind, buf); 622 | 623 | return 0; 624 | } 625 | 626 | /* Dispatch server write state, following socks5 RFC 627 | * In each state, it deal with write buf on soc and 628 | * change state to next 629 | * 630 | * Return: 631 | * -1, error something happen we need to disconnect the client 632 | * 0, success 633 | */ 634 | int dispatch_server_write(s_socket *soc, s_socket *soc_stream, s_socks *socks, 635 | s_buffer *buf, s_socks_conf *conf) 636 | { 637 | int k = 0; 638 | 639 | socklen_t socklen = sizeof(int); 640 | if ( soc->con == 0 ) { 641 | if ( getsockopt(soc->soc, SOL_SOCKET, SO_ERROR, &k, &socklen) < 0) { 642 | perror("getsockopt"); 643 | k = -1; 644 | return k; 645 | } 646 | 647 | if (k != 0) { 648 | ERROR(L_VERBOSE, "server [%d]: error %d", socks->id, k); 649 | k = -1; 650 | return k; 651 | } 652 | 653 | /* Recovering the client address and port after the connection*/ 654 | if ( bor_getsockname_in(soc->soc, &soc->adrC) < 0 ) { 655 | k = -1; 656 | return k; 657 | } 658 | TRACE(L_VERBOSE, "server [%d]: server connection on %s OK",socks->id, 659 | bor_adrtoa_in(&soc->adrS)); 660 | soc->con = 1; 661 | return 0; 662 | } 663 | switch(socks->state) { 664 | case S_W_VER_ACK: 665 | WRITE_DISP(k, soc, buf); 666 | 667 | if ( socks->method == 0x02 ) 668 | socks->state = S_R_AUTH; 669 | else 670 | socks->state = S_R_REQ; 671 | 672 | break; 673 | 674 | case S_W_AUTH_ACK: 675 | WRITE_DISP(k, soc, buf); 676 | if ( socks->auth == 0 ) { 677 | /* close_socket(soc); */ 678 | k = -1; 679 | break; 680 | } 681 | socks->state = S_R_REQ; 682 | break; 683 | 684 | case S_W_REQ_ACK: 685 | if ( buf_empty(buf) ) { 686 | if ( socks->version == SOCKS4_V ) { 687 | build_request_ack4(socks, conf, 688 | soc_stream, NULL, 689 | buf); 690 | } else { 691 | build_request_ack(socks, conf, 692 | soc_stream, NULL, 693 | buf); 694 | } 695 | } 696 | 697 | WRITE_DISP(k, soc, buf); 698 | /* If listen and not connected we are in bind mode */ 699 | if ( socks->listen == 1 && socks->connected == 0 ) { 700 | /* Wait until a soc_bind accept a connection */ 701 | socks->state = S_WAIT; 702 | } else if (socks->connected == 1) { 703 | write_log(socks, soc, soc_stream); 704 | /* We are connected let's go */ 705 | socks->state = S_REPLY; 706 | } else { 707 | /* Error not connected, normally can happen only in bind mode 708 | * we return a error */ 709 | k = -1; 710 | } 711 | break; 712 | 713 | case S_REPLY: 714 | k = write_socks(soc, buf); 715 | if (k < 0) { 716 | /* close_socket(soc); */ break; /* Error */ 717 | } 718 | init_buffer(buf); 719 | break; 720 | 721 | default: 722 | break; 723 | } 724 | 725 | return k; 726 | } 727 | 728 | /* Dispatch server read state, following socks5 RFC 729 | * In each state, it deal with read in buf with soc, 730 | * test the packet with right function, build a reponse and 731 | * change state to next. 732 | * 733 | * Return: 734 | * -1, error something happen we need to disconnect the client 735 | * 0, success 736 | */ 737 | int dispatch_server_read(s_socket *soc, s_socket *soc_stream, s_socket *soc_bind, 738 | s_socks *socks, s_buffer *buf, s_buffer *buf_stream, s_socks_conf *conf) { 739 | int k = 0; 740 | struct sockaddr_in adrC, adrS; 741 | 742 | switch(socks->state) { 743 | case S_R_VER: 744 | READ_DISP(k, soc, buf, 3); 745 | 746 | k = test_version(socks, conf, buf); 747 | 748 | if (k < 0) { 749 | /* close_socket(soc); */ break; /* Error */ 750 | } 751 | if ( socks->version == SOCKS4_V ) { 752 | k = test_request4(socks, 753 | soc_stream, soc_bind, 754 | conf, buf); 755 | init_buffer(buf); 756 | if (k < 0) { 757 | break; /* Error */ 758 | } 759 | 760 | socks->state = S_WAIT; 761 | break; 762 | } 763 | 764 | build_version_ack(socks, conf, 765 | buf); 766 | 767 | socks->state = S_W_VER_ACK; 768 | 769 | break; 770 | 771 | case S_R_AUTH: 772 | READ_DISP(k, soc, buf, 4); 773 | 774 | k = test_auth(socks, conf, 775 | buf); 776 | if (k < 0) { 777 | /* close_socket(soc); */ break; /* Error */ 778 | } 779 | 780 | build_auth_ack(socks, conf, 781 | buf); 782 | 783 | socks->state = S_W_AUTH_ACK; 784 | 785 | break; 786 | 787 | case S_R_REQ: 788 | if ( socks->mode == M_DYNAMIC) { 789 | READ_DISP(k, soc, buf, 790 | sizeof(Socks5Req) + 4); 791 | soc_stream->soc = new_client_socket(conf->config.cli->sockshost, 792 | conf->config.cli->socksport, 793 | &adrC, &adrS); 794 | 795 | if ( soc_stream->soc < 0 ) { 796 | ERROR(L_NOTICE, "client: connection to socks5 server impossible!"); 797 | k = -1; 798 | /* close_socket(soc); */ 799 | } 800 | 801 | #ifdef HAVE_LIBSSL 802 | /* Init SSL here 803 | */ 804 | if (soc_stream->want_ssl == 1) { 805 | TRACE(L_DEBUG, "client: socks5 enable ssl ..."); 806 | soc_stream->ssl = ssl_neogiciate_client(soc_stream->soc); 807 | if ( soc_stream->ssl == NULL ) { 808 | ERROR(L_VERBOSE, "client: ssl error"); 809 | return -3; 810 | } 811 | TRACE(L_DEBUG, "client: ssl ok."); 812 | } 813 | #endif /* HAVE_LIBSSL */ 814 | 815 | socks->state = S_WAIT; 816 | break; 817 | } 818 | 819 | READ_DISP(k, soc, buf, sizeof(Socks5Req)); 820 | 821 | k = analyse_request(socks, soc_stream, soc_bind, conf, buf); 822 | if (k == -EAGAIN) { 823 | k=0; 824 | break; 825 | } 826 | 827 | init_buffer(buf); 828 | if (k < 0) { 829 | break; /* Error */ 830 | } 831 | 832 | socks->state = S_WAIT; 833 | break; 834 | 835 | case S_REPLY: 836 | if ( buf_free(buf_stream) > 0 ) { 837 | k = read_socks(soc, buf_stream, 0); 838 | if (k < 0) { 839 | /* close_socket(soc); */ break; /* Error */ 840 | } 841 | } 842 | break; 843 | default: 844 | break; 845 | } 846 | return k; 847 | } 848 | 849 | /* Dispatch server, it's normally called after a select 850 | * Search client with socket in set_read and set_write and call 851 | * the right dispatcher. 852 | * 853 | * It's responsible for disconnecting the client 854 | * in case of protocol error or network error. 855 | */ 856 | int dispatch_server(s_client *client, fd_set *set_read, fd_set *set_write) 857 | { 858 | int k = 0; 859 | 860 | /* Dispatch server socket */ 861 | if (client->soc.soc != -1 && FD_ISSET (client->soc.soc, set_read)) 862 | k = dispatch_server_read(&client->soc, &client->soc_stream, &client->soc_bind, 863 | &client->socks, &client->buf, &client->stream_buf, client->conf); 864 | 865 | else if (client->soc.soc != -1 && 866 | FD_ISSET (client->soc.soc, set_write)) 867 | k = dispatch_server_write(&client->soc, &client->soc_stream, &client->socks, &client->buf, client->conf); 868 | if (k < 0) { 869 | if (client->soc.con == 0) { 870 | k = -2; 871 | } 872 | disconnection(client); 873 | } 874 | 875 | /* Dispatch stream socket */ 876 | if (client->socks.connected == 0 && client->soc_stream.soc != -1) { 877 | if (FD_ISSET (client->soc_stream.soc, set_write)) { 878 | client->socks.state = S_W_REQ_ACK; 879 | } 880 | } else if (client->soc_stream.soc != -1 881 | && FD_ISSET (client->soc_stream.soc, set_read)) { 882 | if ( buf_free(&client->buf) > 0 ) { 883 | k = read_socks(&client->soc_stream, &client->buf, 0); 884 | if (k < 0) { 885 | disconnection(client); /* Error */ 886 | } 887 | } 888 | 889 | } else if (client->soc_stream.soc != -1 890 | && FD_ISSET (client->soc_stream.soc, set_write)) { 891 | 892 | k = write_socks(&client->soc_stream, &client->stream_buf); 893 | if (k < 0) { 894 | disconnection(client); /* Error */ 895 | } 896 | init_buffer(&client->stream_buf); 897 | } 898 | 899 | if (client->soc_bind.soc != -1 && 900 | FD_ISSET (client->soc_bind.soc, set_read)) { 901 | if ( build_request_accept_bind(&client->socks, client->conf, 902 | &client->soc_stream, &client->soc_bind, &client->buf) == 0 ) { 903 | client->socks.state = S_W_REQ_ACK; 904 | } 905 | } 906 | 907 | return k; 908 | } 909 | 910 | /* Prepare set_read and set_write for a select (ssocksd) 911 | * Initialize set_read and set_write with right socket in function of socks state 912 | * It's responsible to set maxfd to max soc->soc value in set_read or set_write 913 | */ 914 | void init_select_server_cli (s_socket *soc, s_socks *s, s_buffer *buf, 915 | s_buffer *buf_stream, int *maxfd, fd_set *set_read, fd_set *set_write) { 916 | if ( soc->soc != -1 && soc->con == 0 ) { 917 | FD_SET(soc->soc, set_write); 918 | if (soc->soc > *maxfd) *maxfd = soc->soc; 919 | } else if ( soc->soc != -1 ) { 920 | if ( s->state == S_R_VER || 921 | s->state == S_R_AUTH || 922 | s->state == S_R_REQ ) 923 | { 924 | FD_SET(soc->soc, set_read); 925 | } else if (s->state == S_W_VER_ACK || 926 | s->state == S_W_AUTH_ACK || 927 | s->state == S_W_REQ_ACK) 928 | { 929 | FD_SET(soc->soc, set_write); 930 | } else if (s->state == S_WAIT ) { 931 | 932 | } else if (s->state == S_REPLY ) { 933 | if ( buf_empty(buf) == 0 ) { 934 | FD_SET(soc->soc, set_write); 935 | } else if ( buf_free(buf_stream) > 0 ) { 936 | FD_SET(soc->soc, set_read); 937 | } 938 | } 939 | if (soc->soc > *maxfd) *maxfd = soc->soc; 940 | } 941 | } 942 | 943 | /* Prepare set_read and set_write for a select (read and reply) 944 | * Initialize set_read and set_write with right socket in function of socks state 945 | * It's responsible to set maxfd to max soc->soc value in set_read or set_write 946 | */ 947 | void init_select_server_stream (s_socket *soc, s_socks *socks, s_buffer *buf, 948 | s_buffer *buf_stream, int *maxfd, fd_set *set_read, fd_set *set_write) { 949 | if ( soc->soc != -1 ) { 950 | if ( socks->connected == 0) { 951 | FD_SET(soc->soc, set_write); 952 | } else if ( buf_empty(buf) == 0 ) { 953 | FD_SET(soc->soc, set_write); 954 | } else if ( buf_free(buf_stream) > 0 ) { 955 | FD_SET(soc->soc, set_read); 956 | } 957 | if (soc->soc > *maxfd) *maxfd = soc->soc; 958 | } 959 | } 960 | 961 | /* TODO: init_select_server 962 | */ 963 | void init_select_server (int soc_ec, s_client *tc, int *maxfd, 964 | fd_set *set_read, fd_set *set_write) 965 | { 966 | int nc; 967 | /* TODO: move FD_ZERO */ 968 | FD_ZERO (set_read); 969 | FD_ZERO (set_write); 970 | FD_SET (soc_ec, set_read); 971 | 972 | *maxfd = soc_ec; 973 | for (nc = 0; nc < MAXCLI; nc++) { 974 | s_client *client = &tc[nc]; 975 | 976 | init_select_server_cli(&client->soc, &client->socks, &client->buf, &client->stream_buf, 977 | maxfd, set_read, set_write); 978 | 979 | init_select_server_stream(&client->soc_stream, &client->socks, &client->stream_buf, &client->buf, 980 | maxfd, set_read, set_write); 981 | 982 | 983 | if ( client->soc_bind.soc != -1 ) { 984 | FD_SET(client->soc_bind.soc, set_read); 985 | if (client->soc_bind.soc > *maxfd) *maxfd = client->soc_bind.soc; 986 | } 987 | } 988 | } 989 | 990 | int init_select_server_reverse (s_client *tc, int *maxfd, 991 | int ncon, fd_set *set_read, fd_set *set_write, int ssl) 992 | { 993 | /* Security to avoid segmentation fault on tc tab */ 994 | if ( ncon >= MAXCLI ) ncon = MAXCLI-1; 995 | 996 | int nc, cpt = 0; 997 | 998 | FD_ZERO (set_read); 999 | FD_ZERO (set_write); 1000 | 1001 | *maxfd = 0; 1002 | for (nc = 0; nc < MAXCLI; nc++) { 1003 | s_client *client = &tc[nc]; 1004 | 1005 | /* Count available connection */ 1006 | if ( client->soc.soc != -1 ) cpt++; 1007 | 1008 | init_select_server_cli(&client->soc, &client->socks, &client->buf, &client->stream_buf, 1009 | maxfd, set_read, set_write); 1010 | 1011 | init_select_server_stream(&client->soc_stream, &client->socks, &client->stream_buf, &client->buf, 1012 | maxfd, set_read, set_write); 1013 | 1014 | 1015 | if ( client->soc_bind.soc != -1 ) { 1016 | FD_SET(client->soc_bind.soc, set_read); 1017 | if (client->soc_bind.soc > *maxfd) *maxfd = client->soc_bind.soc; 1018 | } 1019 | } 1020 | 1021 | /* */ 1022 | while(cpt < ncon) { 1023 | /* Open connection to the socks client */ 1024 | for (nc = 0; nc < MAXCLI; nc++) if ( tc[nc].soc.soc == -1 ) break; 1025 | if (nc >= MAXCLI) return -1; 1026 | /* Remove nonblockant for ssl */ 1027 | tc[nc].soc.soc = new_client_socket(tc[nc].conf->config.cli->sockshost, 1028 | tc[nc].conf->config.cli->socksport, &tc[nc].soc.adrC, 1029 | &tc[nc].soc.adrS); 1030 | tc[nc].soc.con = 0; 1031 | if ( tc[nc].soc.soc < 0 ) { 1032 | TRACE(L_DEBUG, "client: connection to %s error", 1033 | tc[nc].conf->config.cli); 1034 | return -1; 1035 | } 1036 | tc[nc].soc.con = 1; /* We block so ok */ 1037 | #ifdef HAVE_LIBSSL 1038 | /* Init SSL here 1039 | */ 1040 | if (ssl == 1) { 1041 | TRACE(L_DEBUG, "client: socks5 enable ssl ..."); 1042 | tc[nc].soc.ssl = ssl_neogiciate_client(tc[nc].soc.soc); 1043 | if ( tc[nc].soc.ssl == NULL ) { 1044 | ERROR(L_VERBOSE, "client: ssl error"); 1045 | return -2; 1046 | } 1047 | TRACE(L_DEBUG, "client: ssl ok."); 1048 | } 1049 | #endif /* HAVE_LIBSSL */ 1050 | 1051 | set_non_blocking(tc[nc].soc.soc); 1052 | 1053 | FD_SET(tc[nc].soc.soc, set_write); 1054 | if (tc[nc].soc.soc > *maxfd) *maxfd = tc[nc].soc.soc; 1055 | //init_select_server_cli(&tc[nc].soc, &tc[nc].socks, &tc[nc].buf, 1056 | //&tc[nc].stream_buf, maxfd, set_read, set_write); 1057 | cpt++; 1058 | } 1059 | 1060 | return 0; 1061 | } 1062 | -------------------------------------------------------------------------------- /src/libsocks/socks5-server.h: -------------------------------------------------------------------------------- 1 | /* 2 | * socks5-server.h 3 | * 4 | * Created on: 2011-04-11 5 | * Author: Hugo Caron 6 | * Email: 7 | * 8 | * Copyright (C) 2011 by Hugo Caron 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | #ifndef SOCKS5_SERVER__H 29 | #define SOCKS5_SERVER__H 30 | 31 | #include "socks-common.h" 32 | #include "client.h" 33 | 34 | 35 | 36 | int build_request_accept_bind(s_socks *s, s_socks_conf *c, 37 | s_socket *stream, s_socket *bind, s_buffer *buf); 38 | void build_request_ack(s_socks *s, s_socks_conf *c, 39 | s_socket *stream, s_socket *bind, s_buffer *buf); 40 | 41 | int test_request_dynamic(s_socks *s, s_socks_conf *c, s_buffer *buf); 42 | int analyse_request(s_socks *s, s_socket *stream, s_socket *bind, 43 | s_socks_conf *c, s_buffer *buf); 44 | 45 | void build_auth_ack(s_socks *s, s_socks_conf *c, s_buffer *buf); 46 | int test_auth(s_socks *s, s_socks_conf *c, s_buffer *buf); 47 | 48 | void build_version_ack(s_socks *s, s_socks_conf *c, s_buffer *buf); 49 | int test_version(s_socks *s, s_socks_conf *c, s_buffer *buf); 50 | 51 | 52 | int dispatch_server(s_client *client, fd_set *set_read, fd_set *set_write); 53 | 54 | int dispatch_server_read(s_socket *soc, s_socket *soc_stream, s_socket *soc_bind, 55 | s_socks *socks, s_buffer *buf, s_buffer *buf_stream, s_socks_conf *conf); 56 | 57 | int dispatch_server_write(s_socket *soc, s_socket *soc_stream, s_socks *socks, 58 | s_buffer *buf, s_socks_conf *conf); 59 | 60 | /* TODO: Implement this function: 61 | void dispatch_server(s_socket *soc, s_socket *soc_stream, s_socket *soc_bind, 62 | s_socks *socks, s_buffer *buf, s_buffer *buf_stream, s_socks_conf *conf, 63 | fd_set *set_read, fd_set *set_write); 64 | */ 65 | 66 | void init_select_server_stream (s_socket *soc, s_socks *socks, s_buffer *buf, 67 | s_buffer *buf_stream, int *maxfd, fd_set *set_read, fd_set *set_write); 68 | void init_select_server_cli (s_socket *soc, s_socks *s, s_buffer *buf, 69 | s_buffer *buf_stream, int *maxfd, fd_set *set_read, fd_set *set_write); 70 | 71 | void init_select_server (int soc_ec, s_client *tc, int *maxfd, 72 | fd_set *set_read, fd_set *set_write); 73 | 74 | int init_select_server_reverse (s_client *tc, int *maxfd, 75 | int ncon, fd_set *set_read, fd_set *set_write, int ssl); 76 | 77 | #endif /* SOCKS5_SERVER__H */ 78 | 79 | -------------------------------------------------------------------------------- /src/libsocks/ssl-util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ssl-util.c 3 | * 4 | * Created on: 2011-04-07 5 | * Author: Hugo Caron 6 | * Email: 7 | * 8 | * Copyright (C) 2011 by Hugo Caron 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | #include "ssl-util.h" 29 | 30 | #ifdef HAVE_LIBSSL 31 | 32 | #include "output-util.h" 33 | 34 | 35 | 36 | 37 | SSL_CTX *ctx; 38 | 39 | int ssl_close(SSL *ssl) { 40 | TRACE(L_DEBUG, "server-ssl: shutdown .."); 41 | if ( ssl == NULL) { 42 | /* ERROR(L_DEBUG, "server-ssl: ssl is null"); */ 43 | return -1; 44 | } 45 | if ( SSL_shutdown(ssl) != 1 ) { 46 | ERR_print_errors_fp(stderr); 47 | return -1; 48 | } 49 | SSL_free(ssl); 50 | 51 | return 0; 52 | } 53 | 54 | void ssl_cleaning() { 55 | TRACE(L_DEBUG, "server-ssl: cleaning ctx structure"); 56 | SSL_CTX_free(ctx); 57 | } 58 | 59 | /*TODO: Write a shutdown function for ssl */ 60 | int ssl_init_client(char *serv_cert) { 61 | const SSL_METHOD *meth; 62 | 63 | /* Create an SSL_METHOD structure 64 | * (choose an SSL/TLS protocol version) */ 65 | meth = SSLv3_method(); 66 | /* Create an SSL_CTX structure */ 67 | ctx = SSL_CTX_new(meth); 68 | if (ctx == NULL) { 69 | ERR_print_errors_fp( stderr); 70 | return -1; 71 | } 72 | 73 | /* Load the RSA CA certificate into the SSL_CTX structure 74 | * This will allow this client to verify the server's 75 | * certificate. */ 76 | if (SSL_CTX_load_verify_locations(ctx, serv_cert, NULL) != 1) { 77 | ERR_print_errors_fp(stderr); 78 | return -1; 79 | } 80 | 81 | /* Set flag in context to require peer (server) certificate 82 | * verification */ 83 | SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); 84 | SSL_CTX_set_verify_depth(ctx, 1); 85 | 86 | return 0; 87 | } 88 | 89 | int ssl_init_server(char *certfile, char *privkeyfile, int type) { 90 | const SSL_METHOD *meth; 91 | 92 | /* Create an SSL_METHOD structure 93 | * (choose an SSL/TLS protocol version) */ 94 | meth = SSLv3_method(); 95 | /* Create an SSL_CTX structure */ 96 | ctx = SSL_CTX_new(meth); 97 | if (ctx == NULL) { 98 | ERR_print_errors_fp( stderr); 99 | return -1; 100 | } 101 | 102 | /* Load the server certificate into the SSL_CTX structure */ 103 | TRACE(L_VERBOSE, "server-ssl: load the server certificate"); 104 | if (SSL_CTX_use_certificate_file(ctx, certfile, type) <= 0) { 105 | ERR_print_errors_fp( stderr); 106 | return -1; 107 | } 108 | 109 | /* Load the private-key corresponding to the server certificate */ 110 | TRACE(L_VERBOSE, "server-ssl: load the private-key"); 111 | if (SSL_CTX_use_PrivateKey_file(ctx, privkeyfile, type) <= 0) { 112 | ERR_print_errors_fp( stderr); 113 | return -1; 114 | } 115 | 116 | TRACE(L_VERBOSE, "server-ssl: check if the server certificate "\ 117 | "and private-key matches"); 118 | /* Check if the server certificate and private-key matches */ 119 | if (!SSL_CTX_check_private_key(ctx)) { 120 | ERROR(L_VERBOSE,"Private key does not match the "\ 121 | "certificate public key"); 122 | return -1; 123 | } 124 | 125 | return 0; 126 | } 127 | 128 | SSL *ssl_neogiciate_client(int soc) { 129 | SSL *ssl; 130 | /* An SSL structure is created */ 131 | ssl = SSL_new (ctx); 132 | if ( ssl == NULL ) { 133 | ERR_print_errors_fp(stderr); 134 | return NULL; 135 | } 136 | 137 | /* Assign the socket into the SSL structure (SSL and socket without BIO) */ 138 | SSL_set_fd(ssl, soc); 139 | 140 | /* Perform SSL Handshake on the SSL server */ 141 | int r = SSL_connect(ssl); 142 | if ( r != 1) { 143 | ERROR(L_VERBOSE, "client-ssl: sucks %d", SSL_get_error(ssl, r)); 144 | ERR_print_errors_fp(stdout); 145 | if ( SSL_shutdown(ssl) != 1 ) { 146 | ERR_print_errors_fp(stderr); 147 | } 148 | return NULL; 149 | } 150 | 151 | return ssl; 152 | } 153 | 154 | SSL *ssl_neogiciate_server(int soc) { 155 | SSL *ssl; 156 | /* TCP connection is ready. A SSL structure is created */ 157 | ssl = SSL_new(ctx); 158 | if ( ssl == NULL ) { 159 | ERR_print_errors_fp(stderr); 160 | return NULL; 161 | } 162 | 163 | /* Assign the socket into the SSL structure (SSL and socket without BIO) */ 164 | SSL_set_fd(ssl, soc); 165 | 166 | /* Perform SSL Handshake on the SSL server */ 167 | int r = SSL_accept(ssl); 168 | if ( r != 1) { 169 | ERROR(L_NOTICE, "server-ssl: sucks %d", SSL_get_error(ssl, r)); 170 | ERR_print_errors_fp(stderr); 171 | if ( SSL_shutdown(ssl) != 1 ) { 172 | ERR_print_errors_fp(stderr); 173 | } 174 | return NULL; 175 | } 176 | 177 | return ssl; 178 | } 179 | 180 | #endif /* HAVE_LIBSSL */ 181 | -------------------------------------------------------------------------------- /src/libsocks/ssl-util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ssl-util.h 3 | * 4 | * Created on: 2011-04-07 5 | * Author: Hugo Caron 6 | * Email: 7 | * 8 | * Copyright (C) 2011 by Hugo Caron 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | 29 | #ifndef SSL_UTIL__H 30 | #define SSL_UTIL__H 31 | 32 | #include 33 | 34 | #ifdef HAVE_LIBSSL 35 | 36 | #include 37 | #include 38 | #include 39 | 40 | extern SSL_CTX *gCtx; 41 | 42 | int ssl_close(SSL *ssl); 43 | void ssl_cleaning(); 44 | 45 | SSL *ssl_neogiciate_server(int soc); 46 | SSL *ssl_neogiciate_client(int soc); 47 | int ssl_init_server(char *certfile, char *privkeyfile, int type); 48 | int ssl_init_client(char *serv_ca_cert); 49 | 50 | #endif /* HAVE_LIBSSL */ 51 | 52 | #endif /* SSL_UTIL__H */ 53 | -------------------------------------------------------------------------------- /src/libsocks/unisocket.h: -------------------------------------------------------------------------------- 1 | #ifndef UNISOCK 2 | #define UNISOCK 3 | 4 | #ifdef _WIN32 5 | #define CLOSE_SOCKET closesocket 6 | #define CLOSE_AND_CLEAN(x) closesocket(x); WSACleanup() 7 | #else 8 | #define CLOSE_SOCKET close 9 | #define CLOSE_AND_CLEAN close 10 | #endif 11 | 12 | #ifdef _WIN32 13 | #include 14 | #include 15 | #include 16 | #define sockaddr_un sockaddr_in 17 | #else 18 | #include /* close */ 19 | #include /* wait */ 20 | #include /* socket, bind, sendto, recvfrom, getsockname */ 21 | #include /* socket domaine AF_UNIX */ 22 | #include /* socket domaine AF_INET */ 23 | #include /* inet_ntoa */ 24 | #include /* gethostbyname */ 25 | #include /* gettimeofday */ 26 | #endif 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /src/nsocks.c: -------------------------------------------------------------------------------- 1 | /* 2 | * nsocks.c 3 | * 4 | * Netcat like who pass through a socks5 5 | * 6 | * Created on: 2011-04-12 7 | * Author: Hugo Caron 8 | * Email: 9 | * 10 | * Copyright (C) 2011 by Hugo Caron 11 | * 12 | * Permission is hereby granted, free of charge, to any person obtaining a copy 13 | * of this software and associated documentation files (the "Software"), to deal 14 | * in the Software without restriction, including without limitation the rights 15 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | * copies of the Software, and to permit persons to whom the Software is 17 | * furnished to do so, subject to the following conditions: 18 | * 19 | * The above copyright notice and this permission notice shall be included in 20 | * all copies or substantial portions of the Software. 21 | * 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 | * THE SOFTWARE. 29 | */ 30 | 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | #ifdef _WIN32 39 | #include "win_getopt.h" 40 | #else 41 | #include 42 | #endif 43 | #include 44 | 45 | 46 | struct globalArgs_t { 47 | char *host; // -h option 48 | unsigned int port; // -p option 49 | unsigned int listen; // -l option 50 | unsigned int verbosity; // -v 51 | 52 | #ifdef HAVE_LIBSSL 53 | unsigned int ssl; // -k option 54 | char *certfile; // -c option 55 | #endif 56 | 57 | char *uname; // -u option 58 | char *passwd; // -p option 59 | 60 | char *sockshost; // -s host:port 61 | int socksport; 62 | 63 | } globalArgs; 64 | 65 | int boucle_princ = 1; 66 | void capte_fin (int sig) { 67 | TRACE(L_VERBOSE, "client: signal %d caught\n", sig); 68 | boucle_princ = 0; 69 | } 70 | 71 | #ifdef _WIN32 72 | DWORD PeekStdin() { 73 | HANDLE handle = GetStdHandle(STD_INPUT_HANDLE); 74 | DWORD bytes_left; 75 | PeekNamedPipe(handle, NULL, 0, NULL, &bytes_left, NULL); 76 | return bytes_left; 77 | } 78 | #endif 79 | 80 | 81 | void netcat_like(s_socket *s) { 82 | 83 | #ifndef _WIN32 84 | /* Catch CTRL-C */ 85 | bor_signal (SIGINT, capte_fin, SA_RESTART); 86 | #endif 87 | 88 | int maxfd=0, res; 89 | fd_set set_read, set_write; 90 | char buf[4096]; 91 | int buf_a = 0, buf_b = 0, k = 0; 92 | 93 | struct timeval t; 94 | t.tv_sec = 0; 95 | #ifndef _WIN32 96 | t.tv_usec = 100; 97 | #else 98 | t.tv_usec = 0; 99 | #endif 100 | 101 | while (boucle_princ) { 102 | FD_ZERO (&set_read); 103 | FD_ZERO (&set_write); 104 | 105 | #ifndef _WIN32 106 | FD_SET (0, &set_read); 107 | #endif 108 | FD_SET (s->soc, &set_read); 109 | if (s->soc > maxfd) maxfd = s->soc; /* Fix maxfd */ 110 | 111 | if ( buf_b - buf_a > 0 ) { 112 | FD_SET (s->soc, &set_write); 113 | } 114 | 115 | 116 | // oh my... why windows, WHY???? U BROKE SELECT T___T 117 | // might be useful: http://seclists.org/nmap-dev/2009/q1/612 118 | 119 | res = select (maxfd+1, &set_read, &set_write, NULL, &t); 120 | if (res > 0) { /* Search eligible sockets */ 121 | 122 | /* Read on stdin ? */ 123 | #ifndef _WIN32 124 | if (FD_ISSET (0, &set_read)) { 125 | k = read(0, buf+buf_b, sizeof(buf)-buf_b-1); 126 | if ( k < 0 ) { 127 | perror("read stdin"); 128 | CLOSE_AND_CLEAN(s->soc); 129 | exit(1); 130 | } 131 | if ( k == 0 ) { 132 | ERROR(L_DEBUG, "client: read 0 bytes on stdin"); 133 | boucle_princ = 0; 134 | } 135 | buf_b += k; 136 | } 137 | #endif 138 | 139 | /* Read on socket ? */ 140 | if (FD_ISSET (s->soc, &set_read)) { 141 | #ifdef HAVE_LIBSSL 142 | if ( s->ssl != NULL ) { 143 | k = SSL_read(s->ssl, buf+buf_b, sizeof(buf)-buf_b-1); 144 | if (k < 0) { 145 | perror("read socket"); 146 | CLOSE_AND_CLEAN(s->soc); 147 | exit(1); 148 | } 149 | if (k == 0) { 150 | ERROR(L_DEBUG, "client: read 0 bytes!"); 151 | boucle_princ = 0; 152 | } 153 | k = write(1, buf, k); 154 | continue; 155 | } 156 | #endif 157 | k = recv(s->soc, buf+buf_b, sizeof(buf)-buf_b-1, 0); 158 | if ( k < 0 ) { 159 | #ifdef _WIN32 160 | // TODO: inspect WSAECONNABORTED/10053 after http rqs 161 | // TODO: spam WSAGetLastError everywhere 162 | ERROR(L_NOTICE, "read failed with %d", WSAGetLastError()); 163 | #else 164 | perror("read socket"); 165 | #endif 166 | CLOSE_AND_CLEAN(s->soc); 167 | exit(1); 168 | } 169 | if ( k == 0 ) { 170 | ERROR(L_DEBUG, "client: read 0 bytes!"); 171 | boucle_princ = 0; 172 | } 173 | //printf("client: read %d bytes in socket\n", k); 174 | k = write(1, buf, k); 175 | } 176 | 177 | /* Write on socket ? */ 178 | if(FD_ISSET (s->soc, &set_write)) { 179 | #ifdef HAVE_LIBSSL 180 | if ( s->ssl != NULL ) { 181 | k = SSL_write(s->ssl, buf+buf_a, buf_b - buf_a); 182 | if (k < 0) { 183 | perror("write socket"); 184 | boucle_princ = 0; 185 | } 186 | buf_a += k; 187 | if ( buf_b - buf_a == 0 ) { 188 | buf_b = 0; 189 | buf_a = 0; 190 | } 191 | continue; 192 | } 193 | #endif 194 | k = send(s->soc, buf+buf_a, buf_b - buf_a, 0); 195 | if ( k < 0 ) { 196 | perror("write socket"); 197 | boucle_princ = 0; 198 | } 199 | buf_a += k; 200 | if ( buf_b - buf_a == 0 ) { 201 | buf_b = 0; 202 | buf_a = 0; 203 | } 204 | } 205 | 206 | } else if ( res == 0) { 207 | /* Timeout */ 208 | 209 | #ifdef _WIN32 210 | if(PeekStdin()) { 211 | k = read(0, buf+buf_b, sizeof(buf)-buf_b-1); 212 | if ( k < 0 ) { 213 | perror("read stdin"); 214 | CLOSE_AND_CLEAN(s->soc); 215 | exit(1); 216 | } 217 | if ( k == 0 ) { 218 | ERROR(L_DEBUG, "client: read 0 bytes on stdin"); 219 | boucle_princ = 0; 220 | } 221 | buf_b += k; 222 | } 223 | #endif 224 | 225 | } else if (res < 0) { 226 | #ifdef _WIN32 227 | ERROR(L_NOTICE, "select failed with %d", WSAGetLastError()); 228 | boucle_princ = 0; 229 | #else 230 | if (errno == EINTR) ; /* Received signal, it does nothing */ 231 | else { 232 | perror ("select"); 233 | boucle_princ = 0; 234 | } 235 | #endif 236 | } 237 | } 238 | } 239 | 240 | 241 | void netcat_socks(char *sockshost, int socksport, 242 | char *host, int port, int listen, 243 | char *uname, char *passwd, 244 | int ssl) { 245 | s_socket s; 246 | 247 | #ifdef _WIN32 248 | WSADATA wsaData; 249 | int wsaInit = WSAStartup(MAKEWORD(2,2), &wsaData); 250 | if (wsaInit != 0) { 251 | ERROR(L_NOTICE, "WSAStartup failed: %d\n", wsaInit); 252 | exit(1); 253 | } 254 | #endif 255 | 256 | int r = new_socket_with_socks(&s, sockshost, socksport, 257 | uname, passwd, host, port, listen, 258 | SOCKS5_V, ssl, 259 | (listen != 0) ? CMD_BIND : CMD_CONNECT); 260 | 261 | if ( r < 1 ) { 262 | ERROR(L_NOTICE, "client: connection error"); 263 | #ifdef _WIN32 264 | WSACleanup(); 265 | #endif 266 | exit(1); 267 | } 268 | 269 | TRACE(L_VERBOSE, "client: established connection"); 270 | netcat_like(&s); 271 | TRACE(L_VERBOSE, "client: close socket ..."); 272 | 273 | #ifdef HAVE_LIBSSL 274 | if(s.ssl != NULL) { 275 | ssl_close(s.ssl); 276 | } 277 | if(globalArgs.ssl == 1) { 278 | ssl_cleaning(); 279 | } 280 | #endif /* HAVE_LIBSSL */ 281 | 282 | 283 | CLOSE_AND_CLEAN(s.soc); 284 | } 285 | 286 | 287 | void usage(char *name) { 288 | printf("nsocks v%s ( Netcat like with Socks5 support )\n", PACKAGE_VERSION); 289 | printf("Actually close on EOF (CTRL-D)\n"); 290 | printf("Usage:\n"); 291 | printf("\t%s --socks localhost:1080 mywebserv.com 80\n", name); 292 | printf("\t%s -s localhost:1080 -u y0ug -p 1234 mywebserv.com 80\n", name); 293 | printf("\t%s -s localhost:1080 -l 8080\n", name); 294 | printf("Options:\n"); 295 | #ifdef HAVE_LIBSSL 296 | printf("\t--cert {certfile.crt} Certificate of dst server (enable SSL)\n"); 297 | #endif 298 | printf("\t--verbose (increase verbose level)\n\n"); 299 | printf("\t--socks {host:port}\n"); 300 | printf("\t--uname {uname}\n"); 301 | printf("\t--passwd {passwd}\n"); 302 | printf("\t--listen {port}\n"); 303 | printf("\n"); 304 | printf("Bug report %s\n", PACKAGE_BUGREPORT); 305 | } 306 | 307 | void parseArg(int argc, char *argv[]) { 308 | memset(&globalArgs, 0, sizeof(globalArgs)); 309 | 310 | int c; 311 | while (1) { 312 | static struct option long_options[] = { 313 | {"help", no_argument, 0, 'h'}, 314 | {"verbose", no_argument, 0, 'v'}, 315 | #ifdef HAVE_LIBSSL 316 | {"cert", required_argument, 0, 'c'}, 317 | #endif 318 | {"socks", required_argument, 0, 's'}, 319 | {"uname", required_argument, 0, 'u'}, 320 | {"passwd", required_argument, 0, 'p'}, 321 | {"listen", required_argument, 0, 'l'}, 322 | {0, 0, 0, 0} 323 | }; 324 | 325 | /* getopt_long stores the option index here. */ 326 | int option_index = 0; 327 | 328 | c = getopt_long (argc, argv, "h?vc:s:u:p:l:", 329 | long_options, &option_index); 330 | 331 | /* Detect the end of the options. */ 332 | if (c == -1) 333 | break; 334 | 335 | char *port; 336 | 337 | switch (c) { 338 | case 0: 339 | /* If this option set a flag, do nothing else now. */ 340 | if (long_options[option_index].flag != 0) 341 | break; 342 | printf ("option %s", long_options[option_index].name); 343 | if (optarg) 344 | printf (" with arg %s", optarg); 345 | printf ("\n"); 346 | break; 347 | 348 | case 'v': 349 | //globalArgs.verbosity++; 350 | verbosity++; 351 | break; 352 | 353 | #ifdef HAVE_LIBSSL 354 | case 'c': 355 | globalArgs.ssl = 1; 356 | globalArgs.certfile = optarg; 357 | break; 358 | case 'k': 359 | globalArgs.ssl = 1; 360 | break; 361 | #endif 362 | 363 | case 's': 364 | 365 | port = strchr(optarg, ':'); 366 | if ( port == NULL ) { 367 | usage(argv[0]); 368 | exit(1); 369 | } 370 | *port = 0; 371 | port++; 372 | globalArgs.sockshost = optarg; 373 | globalArgs.socksport = atoi(port); 374 | /*printf("Connect trought socks %s:%d\n", 375 | globalArgs.sockshost, globalArgs.socksport);*/ 376 | break; 377 | 378 | case 'u': 379 | /* printf("Username: %s\n", optarg); */ 380 | globalArgs.uname = optarg; 381 | break; 382 | 383 | case 'p': 384 | /* printf("Passwd: %s\n", optarg); */ 385 | globalArgs.passwd = optarg; 386 | break; 387 | 388 | case 'l': 389 | /* printf("Listening on port: %d\n", atoi(optarg)); */ 390 | globalArgs.listen = atoi(optarg); 391 | break; 392 | 393 | case '?': 394 | /* getopt_long already printed an error message. */ 395 | usage(argv[0]); 396 | exit(1); 397 | break; 398 | 399 | case 'h': 400 | usage(argv[0]); 401 | exit(1); 402 | break; 403 | 404 | default: 405 | abort (); 406 | } 407 | } 408 | 409 | if (argc - optind == 2 ) { 410 | globalArgs.host = argv[optind++]; 411 | globalArgs.port = atoi(argv[optind++]); 412 | } else if(globalArgs.listen != 0) { 413 | 414 | } else { 415 | usage(argv[0]); 416 | exit(1); 417 | } 418 | 419 | if ( globalArgs.sockshost == NULL || globalArgs.socksport == 0 ) { 420 | usage(argv[0]); 421 | exit(1); 422 | } 423 | 424 | #ifdef HAVE_LIBSSL 425 | /*Initialize ssl with the CA certificate file 426 | */ 427 | if (globalArgs.certfile != NULL) { 428 | SSL_load_error_strings(); /* readable error messages */ 429 | SSL_library_init(); /* initialize library */ 430 | TRACE(L_VERBOSE, "client: init ssl ..."); 431 | if (globalArgs.certfile == NULL) { 432 | ERROR(L_NOTICE, "client: actually need CA certificate file"); 433 | exit(1); 434 | } 435 | if ( ssl_init_client(globalArgs.certfile) != 0) { 436 | ERROR(L_NOTICE, "client: ssl config error"); 437 | exit(1); 438 | } 439 | TRACE(L_VERBOSE, "client: ssl ok."); 440 | } 441 | #endif 442 | } 443 | 444 | int main (int argc, char *argv[]) { 445 | parseArg(argc, argv); 446 | 447 | /*if ( globalArgs.listen != 0 ) 448 | netcat_socks_bind(globalArgs.sockshost, globalArgs.socksport, 449 | "0.0.0.0", globalArgs.listen, 450 | globalArgs.uname, globalArgs.passwd, 451 | #ifdef HAVE_LIBSSL 452 | globalArgs.ssl); 453 | #else 454 | 0); 455 | #endif 456 | else*/ 457 | netcat_socks(globalArgs.sockshost, globalArgs.socksport, 458 | globalArgs.host, globalArgs.port, globalArgs.listen, 459 | globalArgs.uname, globalArgs.passwd, 460 | #ifdef HAVE_LIBSSL 461 | globalArgs.ssl); 462 | #else 463 | 0); 464 | #endif 465 | 466 | exit(0); 467 | } 468 | -------------------------------------------------------------------------------- /src/rcsocks.c: -------------------------------------------------------------------------------- 1 | /* 2 | * rcsocks 3 | * 4 | * Created on: 2011-04-13 5 | * Author: Hugo Caron 6 | * Email: 7 | * 8 | * Copyright (C) 2011 by Hugo Caron 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include 38 | 39 | #ifdef _WIN32 40 | #include "win_getopt.h" 41 | #include 42 | #else 43 | #include 44 | #endif 45 | 46 | 47 | #define PORT 1080 48 | 49 | // global to prevent messing with the stack 50 | // see http://stackoverflow.com/questions/1847789/segmentation-fault-on-large-array-sizes 51 | s_socket socks_pool[MAXCLI]; 52 | s_client tc[MAXCLI]; 53 | 54 | struct globalArgs_t { 55 | char *host; // -h option 56 | unsigned int port; // -p option 57 | unsigned int listen; // -l option 58 | unsigned int verbosity; // -v 59 | unsigned int background;// -b 60 | 61 | #ifdef HAVE_LIBSSL 62 | unsigned int ssl; // -s option 63 | char *filecert; // -c option 64 | char *filekey; // -k option 65 | #endif 66 | 67 | char *uname; // -u option 68 | char *passwd; // -p option 69 | 70 | char *sockshost; // -s host:port 71 | int socksport; 72 | } globalArgs; 73 | 74 | int boucle_princ = 1; 75 | void capte_fin (int sig) { 76 | TRACE(L_VERBOSE, "server: signal %d caught\n", sig); 77 | boucle_princ = 0; 78 | } 79 | 80 | /* 81 | * TODO: Bind localhost not 0.0.0.0 82 | */ 83 | void usage(char *name) { 84 | printf("rcSocks Reverse Client Socks5 v%s\n", PACKAGE_VERSION); 85 | printf("Usage:\n"); 86 | printf("\t%s -p 1088 -l 1080 -b\n", name); 87 | printf("\t%s -p 1088 -l 1080\n", name); 88 | printf("In this config you run rssocks like this:\n"); 89 | printf("rssocks --socks rcsocksserv:1080\n"); 90 | printf("and set your tool to connect trought the socks5 server rcsocksserv:1088\n\n"); 91 | printf("Options:\n"); 92 | printf("\t--verbose (increase verbose level)\n\n"); 93 | printf("\t--listen {port} where rssocks connect back\n"); 94 | printf("\t--port {port} the socks5 port you want\n"); 95 | #ifdef HAVE_LIBSSL 96 | printf("\t--ssl enable secure socks5 protocol\n"); 97 | printf("\t--cert {certfile.crt} Certificate of dst server (enable SSL)\n"); 98 | printf("\t--key {file.pem} set server private key\n"); 99 | #endif 100 | printf("\t--background\n"); 101 | printf("\n"); 102 | printf("Bug report %s\n", PACKAGE_BUGREPORT); 103 | } 104 | 105 | void capte_usr1() { 106 | TRACE(L_DEBUG, "server: catch USR1 signal ..."); 107 | } 108 | 109 | void new_connection_reverse (int soc_ec, s_client *tc, s_socket *socks_pool) 110 | { 111 | int nc, nc2, soc_tmp; 112 | struct sockaddr_in adrC_tmp; 113 | 114 | TRACE(L_DEBUG, "server: connection in progress (reverse) ..."); 115 | soc_tmp = bor_accept_in (soc_ec, &adrC_tmp); 116 | if (soc_tmp < 0) { 117 | return; 118 | } 119 | 120 | /* Search free space in tc[].soc */ 121 | for (nc = 0; nc < MAXCLI; nc++) 122 | if (tc[nc].soc.soc == -1) break; 123 | 124 | /* Search for a relay in socks_pool */ 125 | for (nc2 = 0; nc2 < MAXCLI; nc2++) 126 | if (socks_pool[nc2].soc != -1) break; 127 | 128 | if (nc < MAXCLI && nc2 < MAXCLI) { 129 | init_client(&tc[nc], tc[nc].id, tc[nc].socks.mode, tc[nc].conf); 130 | tc[nc].soc.soc = soc_tmp; 131 | tc[nc].socks.state = S_REPLY; 132 | tc[nc].socks.connected = 1; 133 | 134 | memcpy(&tc[nc].soc_stream, &socks_pool[nc2], sizeof(s_socks)); 135 | 136 | /* Remove from the pool */ 137 | socks_pool[nc2].soc = -1; 138 | 139 | memcpy(&tc[nc].soc.adrC, &adrC_tmp, sizeof(struct sockaddr_in)); 140 | TRACE(L_VERBOSE, "server [%d]: established connection with %s", 141 | nc, bor_adrtoa_in(&adrC_tmp)); 142 | 143 | //append_log_client(&tc[nc], "%s", bor_adrtoa_in(&adrC_tmp)); 144 | //set_non_blocking(tc[nc].soc); 145 | } else { 146 | CLOSE_SOCKET(soc_tmp); 147 | ERROR (L_NOTICE, "server: %s connection refused : too many clients!", 148 | bor_adrtoa_in(&adrC_tmp)); 149 | } 150 | 151 | } 152 | 153 | void new_connection_socket(int soc_ec, s_socket *tc, int ssl) 154 | { 155 | int nc, soc_tmp; 156 | struct sockaddr_in adrC_tmp; 157 | 158 | TRACE(L_DEBUG, "server: connection server in progress (socket) ..."); 159 | soc_tmp = bor_accept_in (soc_ec, &adrC_tmp); 160 | if (soc_tmp < 0) { 161 | return; 162 | } 163 | 164 | /* Search free space in tc[].soc */ 165 | for (nc = 0; nc < MAXCLI; nc++) 166 | if (tc[nc].soc == -1) break; 167 | 168 | if (nc < MAXCLI) { 169 | init_socket(&tc[nc]); 170 | 171 | tc[nc].soc = soc_tmp; 172 | memcpy (&tc[nc].adrC, &adrC_tmp, sizeof(struct sockaddr_in)); 173 | TRACE(L_VERBOSE, "server [%d]: established server connection with %s", 174 | nc, bor_adrtoa_in(&adrC_tmp)); 175 | 176 | #ifdef HAVE_LIBSSL 177 | /* Init SSL here 178 | */ 179 | if ( ssl == 1 ) { 180 | TRACE(L_DEBUG, "server [%d]: socks5 enable ssl ...", nc); 181 | tc[nc].ssl = ssl_neogiciate_server(tc[nc].soc); 182 | if ( tc[nc].ssl == NULL ) { 183 | ERROR(L_VERBOSE, "server [%d]: ssl error", nc); 184 | close_socket(&tc[nc]); 185 | return; 186 | } 187 | TRACE(L_DEBUG, "server [%d]: ssl ok.", nc); 188 | set_non_blocking(tc[nc].soc); 189 | } 190 | #endif /* HAVE_LIBSSL */ 191 | 192 | //append_log_client(&tc[nc], "%s", bor_adrtoa_in(&adrC_tmp)); 193 | //set_non_blocking(tc[nc].soc); 194 | } else { 195 | CLOSE_SOCKET(soc_tmp); 196 | ERROR (L_NOTICE, "server: %s connection refused : too many clients!", 197 | bor_adrtoa_in(&adrC_tmp)); 198 | } 199 | } 200 | 201 | void init_select_reverse (int soc_ec, int soc_ec_cli, s_client *tc, int *maxfd, 202 | fd_set *set_read, fd_set *set_write) 203 | { 204 | int nc; 205 | /* TODO: move FD_ZERO */ 206 | FD_ZERO (set_read); 207 | FD_ZERO (set_write); 208 | 209 | FD_SET (soc_ec, set_read); 210 | FD_SET (soc_ec_cli, set_read); 211 | 212 | *maxfd = soc_ec_cli; 213 | for (nc = 0; nc < MAXCLI; nc++) { 214 | s_client *client = &tc[nc]; 215 | 216 | init_select_server_cli(&client->soc, &client->socks, 217 | &client->buf, &client->stream_buf, maxfd, set_read, set_write); 218 | 219 | init_select_server_stream(&client->soc_stream, &client->socks, 220 | &client->stream_buf, &client->buf, maxfd, set_read, set_write); 221 | 222 | 223 | if ( client->soc_bind.soc != -1 ) { 224 | FD_SET(client->soc_bind.soc, set_read); 225 | if (client->soc_bind.soc > *maxfd) *maxfd = client->soc_bind.soc; 226 | } 227 | } 228 | } 229 | 230 | void server_relay(int port, int listen, int ssl) { 231 | int soc_ec_cli = -1, soc_ec = -1, maxfd, res, nc; 232 | fd_set set_read; 233 | fd_set set_write; 234 | struct sockaddr_in addrS; 235 | 236 | 237 | #ifdef _WIN32 238 | WSADATA wsaData; 239 | int wsaInit = WSAStartup(MAKEWORD(2,2), &wsaData); 240 | if (wsaInit != 0) { 241 | ERROR(L_NOTICE, "WSAStartup failed: %d\n", wsaInit); 242 | exit(1); 243 | } 244 | #endif 245 | 246 | /* Init client tab */ 247 | for (nc = 0; nc < MAXCLI; nc++) 248 | init_socket(&socks_pool[nc]); 249 | 250 | for (nc = 0; nc < MAXCLI; nc++) 251 | init_client (&tc[nc], nc, 0, NULL); 252 | 253 | TRACE(L_NOTICE, "server: set listening client socks relay ..."); 254 | soc_ec = new_listen_socket (NULL, port, MAXCLI, &addrS); 255 | if (soc_ec < 0) goto fin_serveur; 256 | 257 | TRACE(L_NOTICE, "server: set server relay ..."); 258 | soc_ec_cli = new_listen_socket (NULL, listen, MAXCLI, &addrS); 259 | if (soc_ec_cli < 0) goto fin_serveur; 260 | 261 | 262 | if ( globalArgs.background == 1 ) { 263 | #ifndef _WIN32 264 | TRACE(L_NOTICE, "server: background ..."); 265 | if ( daemon(0, 0) != 0 ) { 266 | perror("daemon"); 267 | exit(1); 268 | } 269 | #else 270 | printf("bg mode\n\n"); 271 | FreeConsole(); 272 | #endif 273 | } 274 | 275 | #ifndef _WIN32 276 | bor_signal (SIGINT, capte_fin, SA_RESTART); 277 | 278 | /* TODO: Find a better way to exit the select and recall the init_select 279 | * SIGUSR1 is send by a thread to unblock the select */ 280 | bor_signal (SIGUSR1, capte_usr1, SA_RESTART); 281 | #endif 282 | 283 | 284 | while (boucle_princ) { 285 | init_select_reverse(soc_ec, soc_ec_cli, tc, &maxfd, &set_read, &set_write); 286 | 287 | res = select (maxfd+1, &set_read, &set_write, NULL,NULL); 288 | 289 | if (res > 0) { /* Search eligible sockets */ 290 | 291 | if (FD_ISSET (soc_ec, &set_read)) 292 | new_connection_socket (soc_ec, socks_pool, ssl); 293 | 294 | if (FD_ISSET (soc_ec_cli, &set_read)) 295 | new_connection_reverse (soc_ec_cli, tc, socks_pool); 296 | 297 | for (nc = 0; nc < MAXCLI; nc++) { 298 | dispatch_server(&tc[nc], &set_read, &set_write); 299 | } 300 | } else if ( res == 0) { 301 | /* If timeout was set in select and expired */ 302 | } else if (res < 0) { 303 | if (errno == EINTR) ; /* Received signal, it does nothing */ 304 | else { 305 | perror ("select"); 306 | goto fin_serveur; 307 | } 308 | } 309 | } 310 | 311 | fin_serveur: 312 | #ifdef HAVE_LIBSSL 313 | if (ssl == 1) 314 | ssl_cleaning(); 315 | #endif 316 | printf ("Server: closing sockets ...\n"); 317 | if (soc_ec != -1) CLOSE_SOCKET(soc_ec); 318 | for (nc = 0; nc < MAXCLI; nc++) close_socket(&socks_pool[nc]); 319 | for (nc = 0; nc < MAXCLI; nc++) disconnection(&tc[nc]); 320 | 321 | #ifdef _WIN32 322 | WSACleanup(); 323 | #endif 324 | } 325 | 326 | 327 | void parse_arg(int argc, char *argv[]) { 328 | memset(&globalArgs, 0, sizeof(globalArgs)); 329 | globalArgs.listen = 1088; 330 | globalArgs.port = 1080; 331 | 332 | int c; 333 | while (1) { 334 | static struct option long_options[] = { 335 | {"help", no_argument, 0, 'h'}, 336 | {"verbose", no_argument, 0, 'v'}, 337 | {"background", no_argument, 0, 'b'}, 338 | {"listen", required_argument, 0, 'l'}, 339 | {"port", required_argument, 0, 'p'}, 340 | #ifdef HAVE_LIBSSL 341 | {"ssl", no_argument, 0, 's'}, 342 | {"cert", required_argument, 0, 'c'}, 343 | {"key", required_argument, 0, 'k'}, 344 | #endif 345 | {0, 0, 0, 0} 346 | }; 347 | 348 | /* getopt_long stores the option index here. */ 349 | int option_index = 0; 350 | 351 | c = getopt_long (argc, argv, "h?bvk:sc:p:l:", 352 | long_options, &option_index); 353 | 354 | /* Detect the end of the options. */ 355 | if (c == -1) 356 | break; 357 | 358 | switch (c) { 359 | case 0: 360 | /* If this option set a flag, do nothing else now. */ 361 | if (long_options[option_index].flag != 0) 362 | break; 363 | printf ("option %s", long_options[option_index].name); 364 | if (optarg) 365 | printf (" with arg %s", optarg); 366 | printf ("\n"); 367 | break; 368 | 369 | case 'v': 370 | //globalArgs.verbosity++; 371 | verbosity++; 372 | break; 373 | 374 | #ifdef HAVE_LIBSSL 375 | case 's': 376 | globalArgs.ssl = 1; 377 | break; 378 | case 'c': 379 | globalArgs.filecert = strdup(optarg); 380 | break; 381 | case 'k': 382 | globalArgs.filekey = strdup(optarg); 383 | break; 384 | #endif 385 | 386 | case 'b': 387 | globalArgs.background = 1; 388 | break; 389 | 390 | case 'p': 391 | /* printf("Passwd: %s\n", optarg); */ 392 | globalArgs.port = atoi(optarg); 393 | break; 394 | 395 | case 'l': 396 | /* printf("Listening on port: %d\n", atoi(optarg)); */ 397 | globalArgs.listen = atoi(optarg); 398 | break; 399 | 400 | case '?': 401 | /* getopt_long already printed an error message. */ 402 | usage(argv[0]); 403 | exit(1); 404 | break; 405 | 406 | case 'h': 407 | usage(argv[0]); 408 | exit(1); 409 | break; 410 | 411 | default: 412 | abort (); 413 | } 414 | } 415 | 416 | #ifdef HAVE_LIBSSL 417 | if (globalArgs.ssl == 1) { 418 | SSL_load_error_strings(); /* readable error messages */ 419 | SSL_library_init(); /* initialize library */ 420 | if ( globalArgs.filecert[0] == 0 ) { 421 | ERROR(L_NOTICE, "server: need a certificate file to use ssl"); 422 | exit(1); 423 | } 424 | if ( globalArgs.filekey[0] == 0 ) { 425 | ERROR(L_NOTICE, "server: need a private key file to use ssl"); 426 | exit(1); 427 | } 428 | if ( ssl_init_server(globalArgs.filecert, 429 | globalArgs.filekey, SSL_FILETYPE_PEM) != 0) { 430 | ERROR(L_NOTICE, "server: ssl configuration error"); 431 | exit(1); 432 | } 433 | } 434 | #endif 435 | } 436 | 437 | 438 | int main (int argc, char *argv[]) { 439 | parse_arg(argc, argv); 440 | server_relay(globalArgs.port, globalArgs.listen, 441 | #ifdef HAVE_LIBSSL 442 | globalArgs.ssl 443 | #else 444 | 0 445 | #endif 446 | ); 447 | exit(0); 448 | } 449 | -------------------------------------------------------------------------------- /src/rssocks.c: -------------------------------------------------------------------------------- 1 | /* 2 | * rssocks.c 3 | * 4 | * Created on: 2011-04-13 5 | * Author: Hugo Caron 6 | * Email: 7 | * 8 | * Copyright (C) 2011 by Hugo Caron 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include 38 | 39 | #ifdef _WIN32 40 | #include "win_getopt.h" 41 | #else 42 | #include 43 | #endif 44 | 45 | 46 | #define PORT 1080 47 | 48 | // global to prevent messing with the stack 49 | // see http://stackoverflow.com/questions/1847789/segmentation-fault-on-large-array-sizes 50 | s_client tc[MAXCLI]; 51 | 52 | struct globalArgs_t { 53 | char *host; // -h option 54 | unsigned int port; // -p option 55 | unsigned int verbosity; // -v 56 | unsigned int background;// -b 57 | 58 | #ifdef HAVE_LIBSSL 59 | unsigned int ssl; // -k option 60 | char *certfile; // -c option 61 | #endif 62 | 63 | char *uname; // -u option 64 | char *passwd; // -p option 65 | 66 | char *sockshost; // -s host:port 67 | int socksport; 68 | 69 | int ncon; // -n option 70 | } globalArgs; 71 | 72 | int boucle_princ = 1; 73 | void capte_fin (int sig) { 74 | TRACE(L_VERBOSE, "server: signal %d caught\n", sig); 75 | boucle_princ = 0; 76 | } 77 | 78 | void usage(char *name) { 79 | printf("rsSocks Reverse Socks5 Server v%s\n", PACKAGE_VERSION); 80 | printf("It's a reverse socks5 server, you set the socks arg (host:port)\n"); 81 | printf("to your rcsocks instance. It connect back on and wait for request\n"); 82 | printf("Usage:\n"); 83 | printf("\t%s --socks rcsocksserv:1080 -b\n", name); 84 | printf("\t%s --socks rcsocksserv:1080\n", name); 85 | //printf("\t%s --socks socksserv.com:1080 --uname admin --passwd abcde\n", name); 86 | //printf("\t%s -s socksserv.com:1080 -u admin -p abcde -l 1080 -b\n", name); 87 | printf("Options:\n"); 88 | printf("\t--verbose (increase verbose level)\n\n"); 89 | printf("\t--socks {host:port}\n"); 90 | printf("\t--ncon {nb of reverse connection}\n"); 91 | //printf("\t--uname {uname}\n"); 92 | //printf("\t--passwd {passwd}\n"); 93 | #ifdef HAVE_LIBSSL 94 | printf("\t--cert {certfile.crt} Certificate of dst server (enable SSL)\n"); 95 | #endif 96 | printf("\t--background\n"); 97 | printf("\n"); 98 | printf("Bug report %s\n", PACKAGE_BUGREPORT); 99 | } 100 | 101 | void reverse_server(char *sockshost, int socksport, 102 | char *uname, char *passwd, int ssl, int ncon) { 103 | int soc_ec = -1, maxfd, res, nc, k; 104 | fd_set set_read; 105 | fd_set set_write; 106 | 107 | s_socks_conf conf; 108 | s_socks_client_config config_cli; 109 | s_socks_server_config config_srv; 110 | 111 | #ifdef _WIN32 112 | WSADATA wsaData; 113 | int wsaInit = WSAStartup(MAKEWORD(2,2), &wsaData); 114 | if (wsaInit != 0) { 115 | ERROR(L_NOTICE, "WSAStartup failed: %d\n", wsaInit); 116 | exit(1); 117 | } 118 | #endif 119 | 120 | conf.config.cli = &config_cli; 121 | conf.config.srv = &config_srv; 122 | 123 | char method[] = { 0x00, 0x02 }; 124 | char version[] = { SOCKS5_V }; 125 | conf.config.srv->n_allowed_version = 1; 126 | conf.config.srv->allowed_version = version; 127 | conf.config.srv->n_allowed_method = 1; 128 | conf.config.srv->allowed_method = method; 129 | 130 | 131 | conf.config.cli->n_allowed_method = 2; 132 | conf.config.cli->allowed_method = method; 133 | 134 | /* If no username or password we don't use auth */ 135 | if ( uname == NULL || passwd == NULL ) 136 | --conf.config.cli->n_allowed_method; 137 | 138 | conf.config.cli->loop = 1; 139 | conf.config.cli->host = NULL; 140 | conf.config.cli->port = 0; 141 | conf.config.cli->sockshost = sockshost; 142 | conf.config.cli->socksport = socksport; 143 | conf.config.cli->username = uname; 144 | conf.config.cli->password = passwd; 145 | conf.config.cli->version = version[0]; 146 | 147 | /* Init client tab */ 148 | for (nc = 0; nc < MAXCLI; nc++) init_client (&tc[nc], nc, M_SERVER, &conf); 149 | 150 | 151 | #ifndef _WIN32 152 | if ( globalArgs.background == 1 ) { 153 | TRACE(L_NOTICE, "server: background ..."); 154 | if ( daemon(0, 0) != 0 ) { 155 | perror("daemon"); 156 | exit(1); 157 | } 158 | } 159 | 160 | bor_signal (SIGINT, capte_fin, SA_RESTART); 161 | #endif 162 | 163 | 164 | while (boucle_princ) { 165 | k = init_select_server_reverse(tc, &maxfd, ncon, 166 | &set_read, &set_write, ssl); 167 | if ( k < 0 ) { 168 | break; 169 | } 170 | res = select (maxfd+1, &set_read, &set_write, NULL, NULL); 171 | 172 | if (res > 0) { /* Search eligible sockets */ 173 | for (nc = 0; nc < MAXCLI; nc++) { 174 | k = dispatch_server(&tc[nc], &set_read, &set_write); 175 | if (k == -2 ) { 176 | // Not sure why this was set to exit the loop; much more stable without it 177 | //boucle_princ = 0; 178 | break; 179 | } 180 | } 181 | } else if ( res == 0) { 182 | 183 | } else if (res < 0) { 184 | if (errno == EINTR) ; /* Received signal, it does nothing */ 185 | else { 186 | perror ("select"); 187 | break; 188 | } 189 | } 190 | } 191 | 192 | #ifdef HAVE_LIBSSL 193 | if (ssl == 1) 194 | ssl_cleaning(); 195 | #endif 196 | printf ("Server: closing sockets ...\n"); 197 | if (soc_ec != -1) CLOSE_SOCKET(soc_ec); 198 | for (nc = 0; nc < MAXCLI; nc++) disconnection(&tc[nc]); 199 | 200 | #ifdef _WIN32 201 | WSACleanup(); 202 | #endif 203 | } 204 | 205 | 206 | void parse_arg(int argc, char *argv[]) { 207 | memset(&globalArgs, 0, sizeof(globalArgs)); 208 | globalArgs.ncon = 25; 209 | int c; 210 | while (1) { 211 | static struct option long_options[] = { 212 | {"help", no_argument, 0, 'h'}, 213 | {"verbose", no_argument, 0, 'v'}, 214 | {"background", no_argument, 0, 'b'}, 215 | {"socks", required_argument, 0, 's'}, 216 | {"uname", required_argument, 0, 'u'}, 217 | {"passwd", required_argument, 0, 'p'}, 218 | {"ncon", required_argument, 0, 'n'}, 219 | #ifdef HAVE_LIBSSL 220 | {"cert", required_argument, 0, 'c'}, 221 | #endif 222 | {0, 0, 0, 0} 223 | }; 224 | 225 | /* getopt_long stores the option index here. */ 226 | int option_index = 0; 227 | 228 | c = getopt_long (argc, argv, "h?bvc:s:u:p:l:n:", 229 | long_options, &option_index); 230 | 231 | /* Detect the end of the options. */ 232 | if (c == -1) 233 | break; 234 | 235 | char *port; 236 | 237 | switch (c) { 238 | case 0: 239 | /* If this option set a flag, do nothing else now. */ 240 | if (long_options[option_index].flag != 0) 241 | break; 242 | printf ("option %s", long_options[option_index].name); 243 | if (optarg) 244 | printf (" with arg %s", optarg); 245 | printf ("\n"); 246 | break; 247 | 248 | case 'v': 249 | //globalArgs.verbosity++; 250 | verbosity++; 251 | break; 252 | 253 | #ifdef HAVE_LIBSSL 254 | case 'c': 255 | globalArgs.ssl = 1; 256 | globalArgs.certfile = optarg; 257 | break; 258 | case 'k': 259 | globalArgs.ssl = 1; 260 | break; 261 | #endif 262 | 263 | case 'b': 264 | globalArgs.background = 1; 265 | break; 266 | 267 | case 's': 268 | 269 | port = strchr(optarg, ':'); 270 | if ( port == NULL ) { 271 | usage(argv[0]); 272 | exit(1); 273 | } 274 | *port = 0; 275 | port++; 276 | globalArgs.sockshost = optarg; 277 | globalArgs.socksport = atoi(port); 278 | /*printf("Connect trought socks %s:%d\n", 279 | globalArgs.sockshost, globalArgs.socksport);*/ 280 | break; 281 | 282 | case 'u': 283 | /* printf("Username: %s\n", optarg); */ 284 | globalArgs.uname = optarg; 285 | break; 286 | 287 | case 'p': 288 | /* printf("Passwd: %s\n", optarg); */ 289 | globalArgs.passwd = optarg; 290 | break; 291 | 292 | case 'n': 293 | globalArgs.ncon = atoi(optarg); 294 | break; 295 | 296 | case '?': 297 | /* getopt_long already printed an error message. */ 298 | usage(argv[0]); 299 | exit(1); 300 | break; 301 | 302 | case 'h': 303 | usage(argv[0]); 304 | exit(1); 305 | break; 306 | 307 | default: 308 | abort (); 309 | } 310 | } 311 | 312 | if ( globalArgs.sockshost == NULL || globalArgs.socksport == 0 ) { 313 | usage(argv[0]); 314 | exit(1); 315 | } 316 | #ifdef HAVE_LIBSSL 317 | /*Initialize ssl with the CA certificate file 318 | */ 319 | if (globalArgs.certfile != NULL) { 320 | SSL_load_error_strings(); /* readable error messages */ 321 | SSL_library_init(); /* initialize library */ 322 | TRACE(L_VERBOSE, "client: init ssl ..."); 323 | if (globalArgs.certfile == NULL) { 324 | ERROR(L_NOTICE, "client: actually need CA certificate file"); 325 | exit(1); 326 | } 327 | if ( ssl_init_client(globalArgs.certfile) != 0) { 328 | ERROR(L_NOTICE, "client: ssl config error"); 329 | exit(1); 330 | } 331 | TRACE(L_VERBOSE, "client: ssl ok."); 332 | } 333 | #endif 334 | } 335 | 336 | 337 | int main (int argc, char *argv[]) { 338 | parse_arg(argc, argv); 339 | reverse_server(globalArgs.sockshost, globalArgs.socksport, 340 | globalArgs.uname, globalArgs.passwd, 341 | #ifdef HAVE_LIBSSL 342 | globalArgs.ssl, 343 | #else 344 | 0, 345 | #endif 346 | globalArgs.ncon); 347 | exit(0); 348 | } 349 | -------------------------------------------------------------------------------- /src/ssocks.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ssocks.c 3 | * 4 | * Created on: 2011-04-12 5 | * Author: Hugo Caron 6 | * Email: 7 | * 8 | * Copyright (C) 2011 by Hugo Caron 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include 38 | 39 | #ifdef _WIN32 40 | #include "win_getopt.h" 41 | #else 42 | #include 43 | #endif 44 | 45 | 46 | #define PORT 1080 47 | 48 | // global to prevent messing with the stack 49 | // see http://stackoverflow.com/questions/1847789/segmentation-fault-on-large-array-sizes 50 | s_client tc[MAXCLI]; 51 | 52 | struct globalArgs_t { 53 | char *host; // -h option 54 | unsigned int port; // -p option 55 | unsigned int listen; // -l option 56 | unsigned int verbosity; // -v 57 | unsigned int background;// -b 58 | 59 | #ifdef HAVE_LIBSSL 60 | unsigned int ssl; // -k option 61 | char *certfile; // -c option 62 | #endif 63 | 64 | char *uname; // -u option 65 | char *passwd; // -p option 66 | 67 | char *sockshost; // -s host:port 68 | int socksport; 69 | } globalArgs; 70 | 71 | int boucle_princ = 1; 72 | void capte_fin (int sig) { 73 | TRACE(L_VERBOSE, "server: signal %d caught\n", sig); 74 | boucle_princ = 0; 75 | } 76 | /* 77 | * TODO: Bind localhost not 0.0.0.0 78 | */ 79 | void usage(char *name) { 80 | printf("sSocks Socks5 Server Relay v%s\n", PACKAGE_VERSION); 81 | printf("Run a socks server on your localhost interface, and\n"); 82 | printf("relay all data to the server specified in --socks\n"); 83 | printf("Used to bypass browser limitation with authentication\n"); 84 | printf("Usage:\n"); 85 | printf("\t%s --socks socksserv.com:1080\n", name); 86 | printf("\t%s --socks localhost:1080 --listen 1088\n", name); 87 | printf("\t%s --socks socksserv.com:1080 --uname admin --passwd abcde\n", name); 88 | printf("\t%s -s socksserv.com:1080 -u admin -p abcde -l 1080 -b\n", name); 89 | printf("Options:\n"); 90 | printf("\t--verbose (increase verbose level)\n\n"); 91 | printf("\t--socks {host:port}\n"); 92 | printf("\t--uname {uname}\n"); 93 | printf("\t--passwd {passwd}\n"); 94 | printf("\t--listen {port}\n"); 95 | #ifdef HAVE_LIBSSL 96 | printf("\t--cert {certfile.crt} Certificate of dst server (enable SSL)\n"); 97 | #endif 98 | printf("\t--background\n"); 99 | printf("\n"); 100 | printf("Bug report %s\n", PACKAGE_BUGREPORT); 101 | } 102 | 103 | /* TODO: Non blocking connect */ 104 | void server_relay(char *sockshost, int socksport, int port, 105 | char *uname, char *passwd, int ssl) { 106 | int soc_ec = -1, maxfd, res, nc; 107 | fd_set set_read; 108 | fd_set set_write; 109 | 110 | s_socks_conf conf; 111 | s_socks_client_config config_cli; 112 | s_socks_server_config config_srv; 113 | 114 | #ifdef _WIN32 115 | WSADATA wsaData; 116 | int wsaInit = WSAStartup(MAKEWORD(2,2), &wsaData); 117 | if (wsaInit != 0) { 118 | ERROR(L_NOTICE, "WSAStartup failed: %d\n", wsaInit); 119 | exit(1); 120 | } 121 | #endif 122 | 123 | conf.config.cli = &config_cli; 124 | conf.config.srv = &config_srv; 125 | 126 | char method[] = { 0x00, 0x02 }; 127 | char version[] = { SOCKS5_V, 128 | SOCKS4_V 129 | }; 130 | 131 | conf.config.srv->n_allowed_version = 1; 132 | conf.config.srv->allowed_version = version; 133 | conf.config.srv->n_allowed_method = sizeof(method); 134 | conf.config.srv->allowed_method = method; 135 | 136 | 137 | conf.config.cli->n_allowed_method = 2; 138 | conf.config.cli->allowed_method = method; 139 | 140 | /* If no username or password we don't use auth */ 141 | if ( uname == NULL || passwd == NULL ) 142 | --conf.config.cli->n_allowed_method; 143 | 144 | conf.config.cli->loop = 1; 145 | conf.config.cli->host = NULL; 146 | conf.config.cli->port = 0; 147 | conf.config.cli->sockshost = sockshost; 148 | conf.config.cli->socksport = socksport; 149 | conf.config.cli->username = uname; 150 | conf.config.cli->password = passwd; 151 | conf.config.cli->version = version[0]; 152 | 153 | /* Init client tab */ 154 | for (nc = 0; nc < MAXCLI; nc++) init_client (&tc[nc], nc, M_DYNAMIC, &conf); 155 | 156 | 157 | struct sockaddr_in addrS; 158 | soc_ec = new_listen_socket (NULL, port, MAXCLI, &addrS); 159 | if (soc_ec < 0) goto fin_serveur; 160 | 161 | #ifndef _WIN32 162 | if ( globalArgs.background == 1 ) { 163 | TRACE(L_NOTICE, "server: background ..."); 164 | if ( daemon(0, 0) != 0 ) { 165 | perror("daemon"); 166 | exit(1); 167 | } 168 | } 169 | 170 | bor_signal (SIGINT, capte_fin, SA_RESTART); 171 | #endif 172 | 173 | while (boucle_princ) { 174 | init_select_dynamic (soc_ec, tc, &maxfd, &set_read, &set_write); 175 | 176 | res = select (maxfd+1, &set_read, &set_write, NULL, NULL); 177 | 178 | if (res > 0) { /* Search eligible sockets */ 179 | if (FD_ISSET (soc_ec, &set_read)) { 180 | nc = new_connection (soc_ec, tc, 0); 181 | if ( ssl == 1 && nc > -1) 182 | tc[nc].soc_stream.want_ssl = 1; 183 | } 184 | 185 | for (nc = 0; nc < MAXCLI; nc++) { 186 | dispatch_dynamic(&tc[nc], &set_read, &set_write); 187 | } 188 | 189 | } else if ( res == 0) { 190 | /* If timeout was set in select and expired */ 191 | } else if (res < 0) { 192 | if (errno == EINTR) ; /* Received signal, it does nothing */ 193 | else { 194 | perror ("select"); 195 | goto fin_serveur; 196 | } 197 | } 198 | } 199 | 200 | fin_serveur: 201 | 202 | printf ("Server: closing sockets ...\n"); 203 | if (soc_ec != -1) CLOSE_SOCKET(soc_ec); 204 | for (nc = 0; nc < MAXCLI; nc++) disconnection(&tc[nc]); 205 | 206 | #ifdef HAVE_LIBSSL 207 | if (ssl == 1) 208 | ssl_cleaning(); 209 | #endif 210 | #ifdef _WIN32 211 | WSACleanup(); 212 | #endif 213 | } 214 | 215 | 216 | void parseArg(int argc, char *argv[]) { 217 | memset(&globalArgs, 0, sizeof(globalArgs)); 218 | globalArgs.listen = 1080; 219 | 220 | int c; 221 | while (1) { 222 | static struct option long_options[] = { 223 | {"help", no_argument, 0, 'h'}, 224 | {"verbose", no_argument, 0, 'v'}, 225 | {"background", no_argument, 0, 'b'}, 226 | {"socks", required_argument, 0, 's'}, 227 | {"uname", required_argument, 0, 'u'}, 228 | {"passwd", required_argument, 0, 'p'}, 229 | {"listen", required_argument, 0, 'l'}, 230 | #ifdef HAVE_LIBSSL 231 | {"cert", required_argument, 0, 'c'}, 232 | #endif 233 | {0, 0, 0, 0} 234 | }; 235 | 236 | /* getopt_long stores the option index here. */ 237 | int option_index = 0; 238 | 239 | c = getopt_long (argc, argv, "h?bvc:s:u:p:l:", 240 | long_options, &option_index); 241 | 242 | /* Detect the end of the options. */ 243 | if (c == -1) 244 | break; 245 | 246 | char *port; 247 | 248 | switch (c) { 249 | case 0: 250 | /* If this option set a flag, do nothing else now. */ 251 | if (long_options[option_index].flag != 0) 252 | break; 253 | printf ("option %s", long_options[option_index].name); 254 | if (optarg) 255 | printf (" with arg %s", optarg); 256 | printf ("\n"); 257 | break; 258 | 259 | case 'v': 260 | //globalArgs.verbosity++; 261 | verbosity++; 262 | break; 263 | 264 | #ifdef HAVE_LIBSSL 265 | case 'c': 266 | globalArgs.ssl = 1; 267 | globalArgs.certfile = optarg; 268 | break; 269 | case 'k': 270 | globalArgs.ssl = 1; 271 | break; 272 | #endif 273 | 274 | case 'b': 275 | globalArgs.background = 1; 276 | break; 277 | 278 | case 's': 279 | 280 | port = strchr(optarg, ':'); 281 | if ( port == NULL ) { 282 | usage(argv[0]); 283 | exit(1); 284 | } 285 | *port = 0; 286 | port++; 287 | globalArgs.sockshost = optarg; 288 | globalArgs.socksport = atoi(port); 289 | /*printf("Connect trought socks %s:%d\n", 290 | globalArgs.sockshost, globalArgs.socksport);*/ 291 | break; 292 | 293 | case 'u': 294 | /* printf("Username: %s\n", optarg); */ 295 | globalArgs.uname = optarg; 296 | break; 297 | 298 | case 'p': 299 | /* printf("Passwd: %s\n", optarg); */ 300 | globalArgs.passwd = optarg; 301 | break; 302 | 303 | case 'l': 304 | /* printf("Listening on port: %d\n", atoi(optarg)); */ 305 | globalArgs.listen = atoi(optarg); 306 | break; 307 | 308 | case '?': 309 | /* getopt_long already printed an error message. */ 310 | usage(argv[0]); 311 | exit(1); 312 | break; 313 | 314 | case 'h': 315 | usage(argv[0]); 316 | exit(1); 317 | break; 318 | 319 | default: 320 | abort (); 321 | } 322 | } 323 | 324 | if ( globalArgs.sockshost == NULL || globalArgs.socksport == 0 ) { 325 | usage(argv[0]); 326 | exit(1); 327 | } 328 | #ifdef HAVE_LIBSSL 329 | /*Initialize ssl with the CA certificate file 330 | */ 331 | if (globalArgs.certfile != NULL) { 332 | SSL_load_error_strings(); /* readable error messages */ 333 | SSL_library_init(); /* initialize library */ 334 | TRACE(L_VERBOSE, "client: init ssl ..."); 335 | if (globalArgs.certfile == NULL) { 336 | ERROR(L_NOTICE, "client: actually need CA certificate file"); 337 | exit(1); 338 | } 339 | if ( ssl_init_client(globalArgs.certfile) != 0) { 340 | ERROR(L_NOTICE, "client: ssl config error"); 341 | exit(1); 342 | } 343 | TRACE(L_VERBOSE, "client: ssl ok."); 344 | } 345 | #endif 346 | } 347 | 348 | 349 | int main (int argc, char *argv[]) { 350 | parseArg(argc, argv); 351 | server_relay(globalArgs.sockshost, globalArgs.socksport, globalArgs.listen, 352 | globalArgs.uname, globalArgs.passwd, 353 | #ifdef HAVE_LIBSSL 354 | globalArgs.ssl 355 | #else 356 | 0 357 | #endif 358 | ); 359 | exit(0); 360 | } 361 | -------------------------------------------------------------------------------- /src/ssocksd.auth: -------------------------------------------------------------------------------- 1 | # Password file for ssocksd 2 | # Format username:password 3 | # Actually in plain text, kill me! 4 | # More info man 5 ssocksd.auth 5 | 6 | admin:abcde 7 | -------------------------------------------------------------------------------- /src/ssocksd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * ssocksd.c 3 | * 4 | * Created on: 2011-03-30 5 | * Author: Hugo Caron 6 | * Email: 7 | * 8 | * Copyright (C) 2011 by Hugo Caron 9 | * 10 | * Permission is hereby granted, free of charge, to any person obtaining a copy 11 | * of this software and associated documentation files (the "Software"), to deal 12 | * in the Software without restriction, including without limitation the rights 13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | * copies of the Software, and to permit persons to whom the Software is 15 | * furnished to do so, subject to the following conditions: 16 | * 17 | * The above copyright notice and this permission notice shall be included in 18 | * all copies or substantial portions of the Software. 19 | * 20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | * THE SOFTWARE. 27 | */ 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | #include "auth-util.h" 39 | 40 | #include "configd-util.h" 41 | #include "auth-util.h" 42 | 43 | #ifdef _WIN32 44 | #include "win_getopt.h" 45 | #else 46 | #include 47 | #include 48 | #endif 49 | 50 | #include 51 | 52 | #define DEFAULT_PORT 1080 53 | #define PID_FILE "/var/run/ssocksd.pid" 54 | 55 | // global to prevent messing with the stack 56 | // see http://stackoverflow.com/questions/1847789/segmentation-fault-on-large-array-sizes 57 | s_client tc[MAXCLI]; 58 | 59 | int boucle_princ = 1; 60 | void capte_fin (int sig) { 61 | printf ("serveur: signal %d caught\n", sig); 62 | boucle_princ = 0; 63 | } 64 | 65 | /* TODO: Add --pid-file option to server 66 | */ 67 | void usage(char *name) { 68 | printf("ssockd - Server Socks5 v%s\n", PACKAGE_VERSION); 69 | 70 | printf("Usage:\n"); 71 | printf("\t%s --port 8080\n", name); 72 | printf("\t%s -b 127.0.0.1 --port 8080\n", name); 73 | printf("\t%s --address 127.0.0.1 --port 8080\n", name); 74 | printf("\t%s -p 8080 -a ssocksd.auth -d\n", name); 75 | printf("\t%s -vv\n", name); 76 | printf("\n"); 77 | printf("Options:\n"); 78 | #ifdef HAVE_LIBSSL 79 | printf("\t--ssl enable secure socks5 protocol\n"); 80 | printf("\t--cert {file.crt} set server certificate\n"); 81 | printf("\t--key {file.pem} set server private key\n"); 82 | #endif 83 | printf("\t--daemon daemon mode (background)\n"); 84 | printf("\t--verbose increase verbose level\n\n"); 85 | printf("\t--port {port} listening port (default 1080)\n"); 86 | printf("\t--bind {ip} listening on ip (default all)\n"); 87 | printf("\t--file {file} see man 5 ssocksd.conf\n"); 88 | printf("\t--auth {file} see man 5 ssocksd.auth\n"); 89 | printf("\t--log {file} if set connections are log in this file\n"); 90 | printf("\n"); 91 | printf("Bug report %s\n", PACKAGE_BUGREPORT); 92 | } 93 | 94 | void parseArg(int argc, char *argv[]) { 95 | int c; 96 | 97 | globalArgsServer.fileauth[0] = 0; 98 | globalArgsServer.filelog[0] = 0; 99 | globalArgsServer.fileconfig[0] = 0; 100 | globalArgsServer.bindAddr[0] = 0; 101 | globalArgsServer.port = DEFAULT_PORT; 102 | globalArgsServer.verbosity = 0; 103 | globalArgsServer.guest = 1; 104 | globalArgsServer.ssl = 0; 105 | 106 | #ifdef HAVE_LIBSSL 107 | globalArgsServer.filecert[0] = 0; 108 | globalArgsServer.filekey[0] = 0; 109 | #endif 110 | 111 | 112 | while (1) { 113 | static struct option long_options[] = { 114 | {"help", no_argument, 0, 'h'}, 115 | {"verbose", no_argument, 0, 'v'}, 116 | {"daemon", no_argument, 0, 'd'}, 117 | #ifdef HAVE_LIBSSL 118 | {"ssl", no_argument, 0, 's'}, 119 | {"cert", required_argument, 0, 'c'}, 120 | {"key", required_argument, 0, 'k'}, 121 | #endif 122 | {"guest",no_argument, 0, 'g'}, 123 | {"bind", required_argument, 0, 'b'}, 124 | {"port", required_argument, 0, 'p'}, 125 | {"file", required_argument, 0, 'f'}, 126 | {"auth", required_argument, 0, 'a'}, 127 | {"log", required_argument, 0, 'l'}, 128 | {0, 0, 0, 0} 129 | }; 130 | 131 | /* getopt_long stores the option index here. */ 132 | int option_index = 0; 133 | 134 | c = getopt_long (argc, argv, "h?vsgdk:c:f:a:b:p:l:", 135 | long_options, &option_index); 136 | 137 | /* Detect the end of the options. */ 138 | if (c == -1) 139 | break; 140 | 141 | switch (c) { 142 | case 0: 143 | /* If this option set a flag, do nothing else now. */ 144 | if (long_options[option_index].flag != 0) 145 | break; 146 | printf ("option %s", long_options[option_index].name); 147 | if (optarg) 148 | printf (" with arg %s", optarg); 149 | printf ("\n"); 150 | break; 151 | 152 | case 'v': 153 | globalArgsServer.verbosity++; 154 | verbosity++; 155 | break; 156 | 157 | case 'd': 158 | globalArgsServer.daemon = 1; 159 | break; 160 | 161 | #ifdef HAVE_LIBSSL 162 | case 's': 163 | globalArgsServer.ssl = 1; 164 | break; 165 | case 'c': 166 | strncpy_sx(globalArgsServer.filecert, optarg, 167 | sizeof(globalArgsServer.filecert)); 168 | break; 169 | case 'k': 170 | strncpy_sx(globalArgsServer.filekey, optarg, 171 | sizeof(globalArgsServer.filekey)); 172 | break; 173 | #endif 174 | case 'g': 175 | globalArgsServer.guest = 1; 176 | break; 177 | 178 | case 'p': 179 | globalArgsServer.port = atoi(optarg); 180 | break; 181 | 182 | case 'a': 183 | strncpy_sx(globalArgsServer.fileauth, optarg, 184 | sizeof(globalArgsServer.fileauth)); 185 | break; 186 | case 'b': 187 | strncpy_sx(globalArgsServer.bindAddr, optarg, 188 | sizeof(globalArgsServer.bindAddr)); 189 | // globalArgsServer.bindAddr = optarg; 190 | break; 191 | 192 | case 'l': 193 | strncpy_sx(globalArgsServer.filelog, optarg, 194 | sizeof(*globalArgsServer.filelog)); 195 | break; 196 | 197 | case 'f': 198 | strncpy_sx(globalArgsServer.fileconfig, optarg, 199 | sizeof(globalArgsServer.fileconfig)); 200 | if ( loadConfigFile(optarg, &globalArgsServer) < 0 ) { 201 | ERROR(L_NOTICE, "config: config file error"); 202 | ERROR(L_NOTICE, "server: can't start configuration error"); 203 | exit(1); 204 | } 205 | break; 206 | 207 | case '?': 208 | /* getopt_long already printed an error message. */ 209 | usage(argv[0]); 210 | exit(1); 211 | break; 212 | 213 | case 'h': 214 | usage(argv[0]); 215 | exit(1); 216 | break; 217 | 218 | default: 219 | abort (); 220 | } 221 | } 222 | 223 | 224 | if ( globalArgsServer.filelog[0] != 0 ) { 225 | open_log(globalArgsServer.filelog); 226 | } 227 | if ( globalArgsServer.fileauth[0] != 0 ) { 228 | globalArgsServer.guest = 0; 229 | if ( (c = load_auth_file(globalArgsServer.fileauth)) <= 0 ) { 230 | ERROR(L_NOTICE, "auth: no username load"); 231 | ERROR(L_NOTICE, "server: can't start configuration error"); 232 | exit(1); 233 | } else { 234 | TRACE(L_NOTICE, "auth: %d usernames load", c); 235 | } 236 | } else { 237 | TRACE(L_NOTICE, "warning: no authentication enable"); 238 | } 239 | 240 | #ifdef HAVE_LIBSSL 241 | if (globalArgsServer.ssl == 1) { 242 | SSL_load_error_strings(); /* readable error messages */ 243 | SSL_library_init(); /* initialize library */ 244 | if ( globalArgsServer.filecert[0] == 0 ) { 245 | ERROR(L_NOTICE, "server: need a certificate file to use ssl"); 246 | exit(1); 247 | } 248 | if ( globalArgsServer.filekey[0] == 0 ) { 249 | ERROR(L_NOTICE, "server: need a private key file to use ssl"); 250 | exit(1); 251 | } 252 | if ( ssl_init_server(globalArgsServer.filecert, 253 | globalArgsServer.filekey, SSL_FILETYPE_PEM) != 0) { 254 | ERROR(L_NOTICE, "server: ssl configuration error"); 255 | exit(1); 256 | } 257 | } 258 | #endif 259 | 260 | verbosity = globalArgsServer.verbosity; 261 | } 262 | 263 | void capte_usr1() { 264 | TRACE(L_DEBUG, "server: catch USR1 signal ..."); 265 | } 266 | void capte_sigpipe() { 267 | TRACE(L_DEBUG, "server: catch SIGPIPE signal ..."); 268 | } 269 | 270 | void server(const char *bindAddr, int port, int ssl) { 271 | int soc_ec = -1, maxfd, res, nc; 272 | fd_set set_read; 273 | fd_set set_write; 274 | struct sockaddr_in addrS; 275 | char methods[2]; 276 | 277 | #ifdef _WIN32 278 | WSADATA wsaData; 279 | int wsaInit = WSAStartup(MAKEWORD(2,2), &wsaData); 280 | if (wsaInit != 0) { 281 | ERROR(L_NOTICE, "WSAStartup failed: %d\n", wsaInit); 282 | exit(1); 283 | } 284 | #endif 285 | 286 | s_socks_conf conf; 287 | s_socks_server_config config; 288 | conf.config.srv = &config; 289 | 290 | char versions[] = { SOCKS5_V, 291 | SOCKS4_V 292 | }; 293 | 294 | config.allowed_version = versions; 295 | config.n_allowed_version = sizeof(versions); 296 | 297 | if ( globalArgsServer.fileauth[0] != 0 ) { 298 | methods[0] = 0x02; 299 | --config.n_allowed_version; /* Disable socks4 don't support auth */ 300 | } else { 301 | methods[0] = 0x00; 302 | } 303 | 304 | 305 | config.allowed_method = methods; 306 | config.n_allowed_method = 1; 307 | config.check_auth = check_auth; 308 | 309 | /* Init client tab */ 310 | for (nc = 0; nc < MAXCLI; nc++) 311 | init_client (&tc[nc], nc, M_SERVER, &conf); 312 | 313 | if(bindAddr[0] == 0) 314 | soc_ec = new_listen_socket (NULL, port, 0, &addrS); 315 | else 316 | soc_ec = new_listen_socket (bindAddr, port, 0, &addrS); 317 | 318 | if (soc_ec < 0) goto fin_serveur; 319 | 320 | 321 | #ifndef _WIN32 322 | if ( globalArgsServer.daemon == 1 ) { 323 | TRACE(L_NOTICE, "server: mode daemon ..."); 324 | if ( daemon(0, 0) != 0 ) { 325 | perror("daemon"); 326 | exit(1); 327 | } 328 | writePID(PID_FILE); 329 | } 330 | 331 | bor_signal (SIGINT, capte_fin, SA_RESTART); 332 | 333 | /* Need in daemon to remove the PID file properly */ 334 | bor_signal (SIGTERM, capte_fin, SA_RESTART); 335 | bor_signal (SIGPIPE, capte_sigpipe, SA_RESTART); 336 | /* TODO: Find a better way to exit the select and recall the init_select 337 | * SIGUSR1 is send by a thread to unblock the select */ 338 | bor_signal (SIGUSR1, capte_usr1, SA_RESTART); 339 | #endif 340 | 341 | while (boucle_princ) { 342 | init_select_server (soc_ec, tc, &maxfd, &set_read, &set_write); 343 | 344 | res = select (maxfd+1, &set_read, &set_write, NULL, NULL); 345 | 346 | if (res > 0) { /* Search eligible sockets */ 347 | 348 | if (FD_ISSET (soc_ec, &set_read)) 349 | new_connection (soc_ec, tc, ssl); 350 | 351 | for (nc = 0; nc < MAXCLI; nc++) { 352 | dispatch_server(&tc[nc], &set_read, &set_write); 353 | } 354 | 355 | } else if ( res == 0) { 356 | 357 | } else if (res < 0) { 358 | if (errno == EINTR) ; /* Received signal, it does nothing */ 359 | else { 360 | perror ("select"); 361 | goto fin_serveur; 362 | } 363 | } 364 | } 365 | 366 | fin_serveur: 367 | #ifdef HAVE_LIBSSL 368 | if (globalArgsServer.ssl == 1) 369 | ssl_cleaning(); 370 | #endif 371 | TRACE(L_NOTICE, "server: closing sockets ..."); 372 | close_log(); 373 | for (nc = 0; nc < MAXCLI; nc++) disconnection(&tc[nc]); 374 | if (soc_ec != -1) CLOSE_SOCKET(soc_ec); 375 | if ( globalArgsServer.daemon == 1 ) removePID(PID_FILE); 376 | 377 | #ifdef _WIN32 378 | WSACleanup(); 379 | #endif 380 | } 381 | 382 | int main (int argc, char *argv[]) { 383 | parseArg(argc, argv); 384 | server(globalArgsServer.bindAddr, globalArgsServer.port, globalArgsServer.ssl); 385 | exit (0); 386 | } 387 | -------------------------------------------------------------------------------- /src/ssocksd.conf: -------------------------------------------------------------------------------- 1 | # ssocksd configuration file 2 | # More info man 5 ssocksd.conf 3 | 4 | # Listening port 5 | port = 1080 6 | 7 | # If is decomment authentification is on, need to 8 | # have more then credential in file 9 | # auth = /etc/ssocksd.auth 10 | 11 | # Log file if is comment no log of connection 12 | log = /var/log/ssocksd.log 13 | 14 | # Address to listen default bind all 15 | # bind = 127.0.0.1 16 | 17 | # Enable secure version socks5 with ssl 18 | # to use this you need a certificate file 19 | # and a private key 20 | # ssl = 1 21 | # cert = /etc/ssocksd/server.crt 22 | # key = /etc/ssocksd/server.pem 23 | 24 | # Daemon mode if init script start the server 25 | # is automatically in daemon mode 26 | daemon = 0 27 | 28 | # You don't need this just for test 29 | #verbosity = 0 30 | -------------------------------------------------------------------------------- /src/win_getopt.h: -------------------------------------------------------------------------------- 1 | /* Getopt for Microsoft C 2 | This code is a modification of the Free Software Foundation, Inc. 3 | Getopt library for parsing command line argument the purpose was 4 | to provide a Microsoft Visual C friendly derivative. This code 5 | provides functionality for both Unicode and Multibyte builds. 6 | 7 | Date: 02/03/2011 - Ludvik Jerabek - Initial Release 8 | Version: 1.0 9 | Comment: Supports getopt, getopt_long, and getopt_long_only 10 | and POSIXLY_CORRECT environment flag 11 | License: LGPL 12 | 13 | Revisions: 14 | 15 | 02/03/2011 - Ludvik Jerabek - Initial Release 16 | 02/20/2011 - Ludvik Jerabek - Fixed compiler warnings at Level 4 17 | 07/05/2011 - Ludvik Jerabek - Added no_argument, required_argument, optional_argument defs 18 | 08/03/2011 - Ludvik Jerabek - Fixed non-argument runtime bug which caused runtime exception 19 | 08/09/2011 - Ludvik Jerabek - Added code to export functions for DLL and LIB 20 | 02/15/2012 - Ludvik Jerabek - Fixed _GETOPT_THROW definition missing in implementation file 21 | 08/01/2012 - Ludvik Jerabek - Created separate functions for char and wchar_t characters so single dll can do both unicode and ansi 22 | 10/15/2012 - Ludvik Jerabek - Modified to match latest GNU features 23 | 24 | **DISCLAIMER** 25 | THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 26 | EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE 27 | IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 28 | PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE 29 | EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT 30 | APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY 31 | DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY 32 | USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST 33 | PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON 34 | YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE 35 | EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 36 | */ 37 | #ifndef __GETOPT_H_ 38 | #define __GETOPT_H_ 39 | 40 | #ifdef _GETOPT_API 41 | #undef _GETOPT_API 42 | #endif 43 | 44 | #if defined(EXPORTS_GETOPT) && defined(STATIC_GETOPT) 45 | #error "The preprocessor definitions of EXPORTS_GETOPT and STATIC_GETOPT can only be used individually" 46 | #elif defined(STATIC_GETOPT) 47 | #pragma message("Warning static builds of getopt violate the Lesser GNU Public License") 48 | #define _GETOPT_API 49 | #elif defined(EXPORTS_GETOPT) 50 | #pragma message("Exporting getopt library") 51 | #define _GETOPT_API __declspec(dllexport) 52 | #else 53 | #pragma message("Importing getopt library") 54 | #define _GETOPT_API __declspec(dllimport) 55 | #endif 56 | 57 | // Change behavior for C\C++ 58 | #ifdef __cplusplus 59 | #define _BEGIN_EXTERN_C extern "C" { 60 | #define _END_EXTERN_C } 61 | #define _GETOPT_THROW throw() 62 | #else 63 | #define _BEGIN_EXTERN_C 64 | #define _END_EXTERN_C 65 | #define _GETOPT_THROW 66 | #endif 67 | 68 | // Standard GNU options 69 | #define null_argument 0 /*Argument Null*/ 70 | #define no_argument 0 /*Argument Switch Only*/ 71 | #define required_argument 1 /*Argument Required*/ 72 | #define optional_argument 2 /*Argument Optional*/ 73 | 74 | // Shorter Options 75 | #define ARG_NULL 0 /*Argument Null*/ 76 | #define ARG_NONE 0 /*Argument Switch Only*/ 77 | #define ARG_REQ 1 /*Argument Required*/ 78 | #define ARG_OPT 2 /*Argument Optional*/ 79 | 80 | #include 81 | #include 82 | 83 | _BEGIN_EXTERN_C 84 | 85 | extern _GETOPT_API int optind; 86 | extern _GETOPT_API int opterr; 87 | extern _GETOPT_API int optopt; 88 | 89 | // Ansi 90 | struct option_a 91 | { 92 | const char* name; 93 | int has_arg; 94 | int *flag; 95 | char val; 96 | }; 97 | extern _GETOPT_API char *optarg_a; 98 | extern _GETOPT_API int getopt_a(int argc, char *const *argv, const char *optstring) _GETOPT_THROW; 99 | extern _GETOPT_API int getopt_long_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW; 100 | extern _GETOPT_API int getopt_long_only_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW; 101 | 102 | // Unicode 103 | struct option_w 104 | { 105 | const wchar_t* name; 106 | int has_arg; 107 | int *flag; 108 | wchar_t val; 109 | }; 110 | extern _GETOPT_API wchar_t *optarg_w; 111 | extern _GETOPT_API int getopt_w(int argc, wchar_t *const *argv, const wchar_t *optstring) _GETOPT_THROW; 112 | extern _GETOPT_API int getopt_long_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW; 113 | extern _GETOPT_API int getopt_long_only_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW; 114 | 115 | _END_EXTERN_C 116 | 117 | #undef _BEGIN_EXTERN_C 118 | #undef _END_EXTERN_C 119 | #undef _GETOPT_THROW 120 | #undef _GETOPT_API 121 | 122 | #ifdef _UNICODE 123 | #define getopt getopt_w 124 | #define getopt_long getopt_long_w 125 | #define getopt_long_only getopt_long_only_w 126 | #define option option_w 127 | #define optarg optarg_w 128 | #else 129 | #define getopt getopt_a 130 | #define getopt_long getopt_long_a 131 | #define getopt_long_only getopt_long_only_a 132 | #define option option_a 133 | #define optarg optarg_a 134 | #endif 135 | #endif // __GETOPT_H_ 136 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | clr() { 4 | killall ssocks ssocksd nsocks rcsocks rssocks nc 2>/dev/null 5 | } 6 | 7 | hl() { 8 | echo -e "\033[0;33m$*\033[0m" 9 | } 10 | 11 | sdir="${0%/*}" 12 | pushd "${sdir}/build" 13 | clr 14 | 15 | hl "test ssocksd (nc -> ssd -> curl)" 16 | tstr=$(tr /dev/null & 18 | ./ssocksd -p 8081 -d 19 | ret=$(curl -s -x socks5://127.0.0.1:8081 127.0.0.1:8080) 20 | 21 | if [ "$ret" != "$tstr" ]; then 22 | hl "Expected '$tstr', got '$ret'" 23 | exit 1 24 | else hl "ok"; fi 25 | 26 | hl "test ssocks (nc -> ssd -> ss -> curl)" 27 | tstr=$(tr /dev/null & 29 | ./ssocks -s 127.0.0.1:8081 -l 8082 -b 30 | ret=$(curl -s -x socks5://127.0.0.1:8082 127.0.0.1:8080) 31 | 32 | if [ "$ret" != "$tstr" ]; then 33 | hl "Expected '$tstr', got '$ret'" 34 | exit 1 35 | else hl "ok"; fi 36 | 37 | hl "test nsocks (nc -> ssd -> ns)" 38 | tstr=$(tr /dev/null & 40 | ret=$(./nsocks -s 127.0.0.1:8081 127.0.0.1 8080 | tail -n 1) 41 | 42 | if [ "$ret" != "$tstr" ]; then 43 | hl "Expected '$tstr', got '$ret'" 44 | exit 1 45 | else hl "ok"; fi 46 | 47 | killall nc 48 | 49 | hl "test r[sc]socks (nc -> rss -> rcs -> curl)" 50 | tstr=$(tr /dev/null & 52 | ./rcsocks -p 8083 -l 8084 -b 53 | ./rssocks -s 127.0.0.1:8083 -b 54 | ret=$(curl -s -x socks5://127.0.0.1:8084 127.0.0.1:8080) 55 | 56 | if [ "$ret" != "$tstr" ]; then 57 | hl "Expected '$tstr', got '$ret'" 58 | exit 1 59 | else hl "ok"; fi 60 | 61 | clr 62 | popd 63 | --------------------------------------------------------------------------------