├── .gitignore ├── README.md ├── bin └── release │ ├── win32 │ ├── install_driver.bat │ ├── netfilter2.sys │ ├── nfapi.dll │ ├── nfregdrv.exe │ └── uninstall_driver.bat │ └── x64 │ ├── install_driver.bat │ ├── netfilter2.sys │ ├── nfapi.dll │ ├── nfregdrv.exe │ └── uninstall_driver.bat ├── include ├── nfapi.h ├── nfdriver_data.h ├── nfevents.h └── samples_config.h ├── lib └── release │ ├── win32 │ ├── nfapi.exp │ └── nfapi.lib │ └── x64 │ ├── nfapi.exp │ └── nfapi.lib ├── license.rtf └── src ├── SocksRedirector.cpp ├── SocksRedirector.vcxproj ├── UdpProxy.h ├── dbglogger.h ├── icmp.h ├── iocp.h ├── linkedlist.h ├── socksdefs.h ├── stdafx.cpp ├── stdafx.h ├── sync.h ├── tcpproxy.h ├── threadpool.h └── utf8.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.filters 2 | *.user 3 | *.sln 4 | .vs/ 5 | SocksRedirector.exe 6 | /src/Debug/ 7 | /src/Release/ 8 | /bin/Debug/ 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SocksRedirector 2 | 3 | Modified `SocksRedirector` demo from [Netfilter SDK](https://netfiltersdk.com/). 4 | It transparently redirects TCP/UDP traffic to a specified SOCKS5 proxy (`wfp2socks`). 5 | WFP level kernel driver is used to filter the transmitted packets. 6 | 7 | ## Usage 8 | See `SocksRedirector.exe --help`. 9 | 10 | Run `install_driver.bat` for installing and registering the network hooking driver. 11 | The driver starts immediately and reboot is not required. 12 | Run `uninstall_driver.bat` to remove the driver from system. 13 | Elevated administrative rights must be activated explicitly for registering the driver (run the scripts using "Run as administrator" context menu item in Windows Explorer). 14 | 15 | ## License 16 | All copyrights to NetFilter SDK are exclusively owned by the author - Vitaly Sidorov. 17 | 18 | ## Note 19 | The pre-built demo driver provided by [Netfilter SDK](https://netfiltersdk.com/) filters no more than 1000000 TCP connections and UDP sockets. 20 | After exceeding this limit the filtering continues again after system reboot. 21 | You may [order](http://www.netfiltersdk.com/buy_now.html) a license for full version or source code. 22 | -------------------------------------------------------------------------------- /bin/release/win32/install_driver.bat: -------------------------------------------------------------------------------- 1 | cd /d %~dp0 2 | 3 | rem Installing the network hooking driver build for 32-bit systems 4 | 5 | rem Copy the driver to system folder 6 | copy netfilter2.sys %windir%\system32\drivers 7 | 8 | rem Register the driver 9 | nfregdrv.exe netfilter2 10 | 11 | pause -------------------------------------------------------------------------------- /bin/release/win32/netfilter2.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dyhkwong/SocksRedirector/7489085ca4f960f4a54f89346f2e2306212eb220/bin/release/win32/netfilter2.sys -------------------------------------------------------------------------------- /bin/release/win32/nfapi.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dyhkwong/SocksRedirector/7489085ca4f960f4a54f89346f2e2306212eb220/bin/release/win32/nfapi.dll -------------------------------------------------------------------------------- /bin/release/win32/nfregdrv.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dyhkwong/SocksRedirector/7489085ca4f960f4a54f89346f2e2306212eb220/bin/release/win32/nfregdrv.exe -------------------------------------------------------------------------------- /bin/release/win32/uninstall_driver.bat: -------------------------------------------------------------------------------- 1 | cd /d %~dp0 2 | 3 | rem Uninstall the network hooking driver 4 | 5 | rem Try to unload the driver 6 | sc stop netfilter2 7 | 8 | rem Unregister the driver 9 | nfregdrv.exe -u netfilter2 10 | 11 | rem Delete driver file 12 | del %windir%\system32\drivers\netfilter2.sys 13 | 14 | pause -------------------------------------------------------------------------------- /bin/release/x64/install_driver.bat: -------------------------------------------------------------------------------- 1 | cd /d %~dp0 2 | 3 | rem Installing the network hooking driver build for 64-bit systems 4 | 5 | rem Copy the driver to system folder 6 | copy netfilter2.sys %windir%\system32\drivers 7 | 8 | rem Register the driver 9 | nfregdrv.exe netfilter2 10 | 11 | pause -------------------------------------------------------------------------------- /bin/release/x64/netfilter2.sys: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dyhkwong/SocksRedirector/7489085ca4f960f4a54f89346f2e2306212eb220/bin/release/x64/netfilter2.sys -------------------------------------------------------------------------------- /bin/release/x64/nfapi.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dyhkwong/SocksRedirector/7489085ca4f960f4a54f89346f2e2306212eb220/bin/release/x64/nfapi.dll -------------------------------------------------------------------------------- /bin/release/x64/nfregdrv.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dyhkwong/SocksRedirector/7489085ca4f960f4a54f89346f2e2306212eb220/bin/release/x64/nfregdrv.exe -------------------------------------------------------------------------------- /bin/release/x64/uninstall_driver.bat: -------------------------------------------------------------------------------- 1 | cd /d %~dp0 2 | 3 | rem Uninstall the network hooking driver 4 | 5 | rem Try to unload the driver 6 | sc stop netfilter2 7 | 8 | rem Unregister the driver 9 | nfregdrv.exe -u netfilter2 10 | 11 | rem Delete driver file 12 | del %windir%\system32\drivers\netfilter2.sys 13 | 14 | pause -------------------------------------------------------------------------------- /include/nfapi.h: -------------------------------------------------------------------------------- 1 | // 2 | // NetFilterSDK 3 | // Copyright (C) Vitaly Sidorov 4 | // All rights reserved. 5 | // 6 | // This file is a part of the NetFilter SDK. 7 | // The code and information is provided "as-is" without 8 | // warranty of any kind, either expressed or implied. 9 | // 10 | 11 | 12 | #ifndef _NFAPI_H 13 | #define _NFAPI_H 14 | 15 | #include "nfevents.h" 16 | 17 | #ifdef _NFAPI_STATIC_LIB 18 | #define NFAPI_API 19 | #else 20 | #ifdef NFAPI_EXPORTS 21 | #define NFAPI_API __declspec(dllexport) 22 | #else 23 | #define NFAPI_API __declspec(dllimport) 24 | #endif 25 | #endif 26 | 27 | // Flags for NF_UDP_OPTIONS.flags 28 | 29 | #define TDI_RECEIVE_BROADCAST 0x00000004 // received TSDU was broadcast. 30 | #define TDI_RECEIVE_MULTICAST 0x00000008 // received TSDU was multicast. 31 | #define TDI_RECEIVE_PARTIAL 0x00000010 // received TSDU is not fully presented. 32 | #define TDI_RECEIVE_NORMAL 0x00000020 // received TSDU is normal data 33 | #define TDI_RECEIVE_EXPEDITED 0x00000040 // received TSDU is expedited data 34 | #define TDI_RECEIVE_PEEK 0x00000080 // received TSDU is not released 35 | #define TDI_RECEIVE_NO_RESPONSE_EXP 0x00000100 // HINT: no back-traffic expected 36 | #define TDI_RECEIVE_COPY_LOOKAHEAD 0x00000200 // for kernel-mode indications 37 | #define TDI_RECEIVE_ENTIRE_MESSAGE 0x00000400 // opposite of RECEIVE_PARTIAL 38 | // (for kernel-mode indications) 39 | #define TDI_RECEIVE_AT_DISPATCH_LEVEL 0x00000800 // receive indication called 40 | // at dispatch level 41 | #define TDI_RECEIVE_CONTROL_INFO 0x00001000 // Control info is being passed up. 42 | #define TDI_RECEIVE_FORCE_INDICATION 0x00002000 // reindicate rejected data. 43 | #define TDI_RECEIVE_NO_PUSH 0x00004000 // complete only when full. 44 | 45 | typedef enum _NF_FLAGS 46 | { 47 | NFF_NONE = 0, 48 | NFF_DONT_DISABLE_TEREDO = 1, 49 | NFF_DONT_DISABLE_TCP_OFFLOADING = 2, 50 | NFF_DISABLE_AUTO_REGISTER = 4, 51 | NFF_DISABLE_AUTO_START = 8, 52 | } NF_FLAGS; 53 | 54 | #ifndef _C_API 55 | namespace nfapi 56 | { 57 | #define NFAPI_NS nfapi:: 58 | #define NFAPI_CC 59 | #else // _C_API 60 | #define NFAPI_CC __cdecl 61 | #define NFAPI_NS 62 | #ifdef __cplusplus 63 | extern "C" 64 | { 65 | #endif 66 | #endif // _C_API 67 | 68 | /** 69 | * Initializes the internal data structures and starts the filtering thread. 70 | * @param driverName The name of hooking driver, without ".sys" extension. 71 | * @param pHandler Pointer to event handling object 72 | **/ 73 | NFAPI_API NF_STATUS NFAPI_CC 74 | nf_init(const char * driverName, NF_EventHandler * pHandler); 75 | 76 | /** 77 | * Stops the filtering thread, breaks all filtered connections and closes 78 | * a connection with the hooking driver. 79 | **/ 80 | NFAPI_API void NFAPI_CC 81 | nf_free(); 82 | 83 | /** 84 | * Registers and starts a driver with specified name (without ".sys" extension) 85 | * @param driverName 86 | **/ 87 | NFAPI_API NF_STATUS NFAPI_CC 88 | nf_registerDriver(const char * driverName); 89 | 90 | /** 91 | * Registers and starts a driver with specified name (without ".sys" extension) and path to driver folder 92 | * @param driverName 93 | * @param driverPath 94 | **/ 95 | NFAPI_API NF_STATUS NFAPI_CC 96 | nf_registerDriverEx(const char * driverName, const char * driverPath); 97 | 98 | /** 99 | * Unregisters a driver with specified name (without ".sys" extension) 100 | * @param driverName 101 | **/ 102 | NFAPI_API NF_STATUS NFAPI_CC 103 | nf_unRegisterDriver(const char * driverName); 104 | 105 | 106 | // 107 | // TCP control routines 108 | // 109 | 110 | /** 111 | * Suspends or resumes indicating of sends and receives for specified connection. 112 | * @param id Connection identifier 113 | * @param suspended TRUE(1) for suspend, FALSE(0) for resume 114 | **/ 115 | NFAPI_API NF_STATUS NFAPI_CC 116 | nf_tcpSetConnectionState(ENDPOINT_ID id, int suspended); 117 | 118 | /** 119 | * Sends the buffer to remote server via specified connection. 120 | * @param id Connection identifier 121 | * @param buf Pointer to data buffer 122 | * @param len Buffer length 123 | **/ 124 | NFAPI_API NF_STATUS NFAPI_CC 125 | nf_tcpPostSend(ENDPOINT_ID id, const char * buf, int len); 126 | 127 | /** 128 | * Indicates the buffer to local process via specified connection. 129 | * @param id Unique connection identifier 130 | * @param buf Pointer to data buffer 131 | * @param len Buffer length 132 | **/ 133 | NFAPI_API NF_STATUS NFAPI_CC 134 | nf_tcpPostReceive(ENDPOINT_ID id, const char * buf, int len); 135 | 136 | /** 137 | * Breaks the connection with given id. 138 | * @param id Connection identifier 139 | **/ 140 | NFAPI_API NF_STATUS NFAPI_CC 141 | nf_tcpClose(ENDPOINT_ID id); 142 | 143 | /** 144 | * Sets the timeout for TCP connections and returns old timeout. 145 | * @param timeout Timeout value in milliseconds. Specify zero value to disable timeouts. 146 | */ 147 | NFAPI_API unsigned long NFAPI_CC 148 | nf_setTCPTimeout(unsigned long timeout); 149 | 150 | /** 151 | * Disables indicating TCP packets to user mode for the specified endpoint 152 | * @param id Socket identifier 153 | */ 154 | NFAPI_API NF_STATUS NFAPI_CC 155 | nf_tcpDisableFiltering(ENDPOINT_ID id); 156 | 157 | 158 | // 159 | // UDP control routines 160 | // 161 | 162 | /** 163 | * Suspends or resumes indicating of sends and receives for specified socket. 164 | * @param id Socket identifier 165 | * @param suspended TRUE(1) for suspend, FALSE(0) for resume 166 | **/ 167 | NFAPI_API NF_STATUS NFAPI_CC 168 | nf_udpSetConnectionState(ENDPOINT_ID id, int suspended); 169 | 170 | /** 171 | * Sends the buffer to remote server via specified socket. 172 | * @param id Socket identifier 173 | * @param options UDP options 174 | * @param remoteAddress Destination address 175 | * @param buf Pointer to data buffer 176 | * @param len Buffer length 177 | **/ 178 | NFAPI_API NF_STATUS NFAPI_CC 179 | nf_udpPostSend(ENDPOINT_ID id, const unsigned char * remoteAddress, const char * buf, int len, PNF_UDP_OPTIONS options); 180 | 181 | /** 182 | * Indicates the buffer to local process via specified socket. 183 | * @param id Unique connection identifier 184 | * @param options UDP options 185 | * @param remoteAddress Source address 186 | * @param buf Pointer to data buffer 187 | * @param len Buffer length 188 | **/ 189 | NFAPI_API NF_STATUS NFAPI_CC 190 | nf_udpPostReceive(ENDPOINT_ID id, const unsigned char * remoteAddress, const char * buf, int len, PNF_UDP_OPTIONS options); 191 | 192 | /** 193 | * Disables indicating UDP packets to user mode for the specified endpoint 194 | * @param id Socket identifier 195 | */ 196 | NFAPI_API NF_STATUS NFAPI_CC 197 | nf_udpDisableFiltering(ENDPOINT_ID id); 198 | 199 | 200 | /** 201 | * Sends a packet to remote IP 202 | * @param buf Pointer to IP packet 203 | * @param len Buffer length 204 | * @param options IP options 205 | **/ 206 | NFAPI_API NF_STATUS NFAPI_CC 207 | nf_ipPostSend(const char * buf, int len, PNF_IP_PACKET_OPTIONS options); 208 | 209 | /** 210 | * Indicates a packet to TCP/IP stack 211 | * @param buf Pointer to IP packet 212 | * @param len Buffer length 213 | * @param options IP options 214 | **/ 215 | NFAPI_API NF_STATUS NFAPI_CC 216 | nf_ipPostReceive(const char * buf, int len, PNF_IP_PACKET_OPTIONS options); 217 | 218 | // 219 | // Filtering rules 220 | // 221 | 222 | /** 223 | * Add a rule to the head of rules list in driver. 224 | * @param pRule See NF_RULE 225 | * @param toHead TRUE (1) - add rule to list head, FALSE (0) - add rule to tail 226 | **/ 227 | NFAPI_API NF_STATUS NFAPI_CC 228 | nf_addRule(PNF_RULE pRule, int toHead); 229 | 230 | /** 231 | * Removes all rules from driver. 232 | **/ 233 | NFAPI_API NF_STATUS NFAPI_CC 234 | nf_deleteRules(); 235 | 236 | /** 237 | * Replace the rules in driver with the specified array. 238 | * @param pRules Array of NF_RULE structures 239 | * @param count Number of items in array 240 | **/ 241 | NFAPI_API NF_STATUS NFAPI_CC 242 | nf_setRules(PNF_RULE pRules, int count); 243 | 244 | /** 245 | * Add a rule to the head of rules list in driver. 246 | * @param pRule See NF_RULE_EX 247 | * @param toHead TRUE (1) - add rule to list head, FALSE (0) - add rule to tail 248 | **/ 249 | NFAPI_API NF_STATUS NFAPI_CC 250 | nf_addRuleEx(PNF_RULE_EX pRule, int toHead); 251 | 252 | /** 253 | * Replace the rules in driver with the specified array. 254 | * @param pRules Array of NF_RULE_EX structures 255 | * @param count Number of items in array 256 | **/ 257 | NFAPI_API NF_STATUS NFAPI_CC 258 | nf_setRulesEx(PNF_RULE_EX pRules, int count); 259 | 260 | // 261 | // Debug routine 262 | // 263 | 264 | NFAPI_API unsigned long NFAPI_CC 265 | nf_getConnCount(); 266 | 267 | NFAPI_API NF_STATUS NFAPI_CC 268 | nf_tcpSetSockOpt(ENDPOINT_ID id, int optname, const char* optval, int optlen); 269 | 270 | /** 271 | * Returns the process name for given process id 272 | * @param processId Process identifier 273 | * @param buf Buffer 274 | * @param len Buffer length 275 | **/ 276 | NFAPI_API BOOL NFAPI_CC 277 | nf_getProcessNameA(DWORD processId, char * buf, DWORD len); 278 | 279 | NFAPI_API BOOL NFAPI_CC 280 | nf_getProcessNameW(DWORD processId, wchar_t * buf, DWORD len); 281 | 282 | #ifdef UNICODE 283 | #define nf_getProcessName nf_getProcessNameW 284 | #else 285 | #define nf_getProcessName nf_getProcessNameA 286 | #endif 287 | 288 | NFAPI_API BOOL NFAPI_CC 289 | nf_getProcessNameFromKernel(DWORD processId, wchar_t * buf, DWORD len); 290 | 291 | /** 292 | * Allows the current process to see the names of all processes in system 293 | **/ 294 | NFAPI_API void NFAPI_CC 295 | nf_adjustProcessPriviledges(); 296 | 297 | /** 298 | * Returns TRUE if the specified process acts as a local proxy, accepting the redirected TCP connections. 299 | **/ 300 | NFAPI_API BOOL NFAPI_CC 301 | nf_tcpIsProxy(DWORD processId); 302 | 303 | /** 304 | * Set the number of worker threads and initialization flags. 305 | * The function should be called before nf_init. 306 | * By default nThreads = 1 and flags = 0 307 | * @param nThreads Number of worker threads for NF_EventHandler events 308 | * @param flags A combination of flags from NF_FLAGS 309 | **/ 310 | NFAPI_API void NFAPI_CC 311 | nf_setOptions(DWORD nThreads, DWORD flags); 312 | 313 | /** 314 | * Complete TCP connect request pended using flag NF_PEND_CONNECT_REQUEST. 315 | **/ 316 | NFAPI_API NF_STATUS NFAPI_CC 317 | nf_completeTCPConnectRequest(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo); 318 | 319 | /** 320 | * Complete UDP connect request pended using flag NF_PEND_CONNECT_REQUEST. 321 | **/ 322 | NFAPI_API NF_STATUS NFAPI_CC 323 | nf_completeUDPConnectRequest(ENDPOINT_ID id, PNF_UDP_CONN_REQUEST pConnInfo); 324 | 325 | /** 326 | * Returns in pConnInfo the properties of TCP connection with specified id. 327 | **/ 328 | NFAPI_API NF_STATUS NFAPI_CC 329 | nf_getTCPConnInfo(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo); 330 | 331 | /** 332 | * Returns in pConnInfo the properties of UDP socket with specified id. 333 | **/ 334 | NFAPI_API NF_STATUS NFAPI_CC 335 | nf_getUDPConnInfo(ENDPOINT_ID id, PNF_UDP_CONN_INFO pConnInfo); 336 | 337 | /** 338 | * Set the event handler for IP filtering events 339 | */ 340 | NFAPI_API void NFAPI_CC 341 | nf_setIPEventHandler(NF_IPEventHandler * pHandler); 342 | 343 | /** 344 | * Add flow control context 345 | */ 346 | NFAPI_API NF_STATUS NFAPI_CC 347 | nf_addFlowCtl(PNF_FLOWCTL_DATA pData, unsigned int * pFcHandle); 348 | 349 | /** 350 | * Delete flow control context 351 | */ 352 | NFAPI_API NF_STATUS NFAPI_CC 353 | nf_deleteFlowCtl(unsigned int fcHandle); 354 | 355 | /** 356 | * Associate flow control context with TCP connection 357 | */ 358 | NFAPI_API NF_STATUS NFAPI_CC 359 | nf_setTCPFlowCtl(ENDPOINT_ID id, unsigned int fcHandle); 360 | 361 | /** 362 | * Associate flow control context with UDP socket 363 | */ 364 | NFAPI_API NF_STATUS NFAPI_CC 365 | nf_setUDPFlowCtl(ENDPOINT_ID id, unsigned int fcHandle); 366 | 367 | /** 368 | * Modify flow control context limits 369 | */ 370 | NFAPI_API NF_STATUS NFAPI_CC 371 | nf_modifyFlowCtl(unsigned int fcHandle, PNF_FLOWCTL_DATA pData); 372 | 373 | /** 374 | * Get flow control context statistics as the numbers of in/out bytes 375 | */ 376 | NFAPI_API NF_STATUS NFAPI_CC 377 | nf_getFlowCtlStat(unsigned int fcHandle, PNF_FLOWCTL_STAT pStat); 378 | 379 | /** 380 | * Get TCP connection statistics as the numbers of in/out bytes. 381 | * The function can be called only from tcpClosed handler! 382 | */ 383 | NFAPI_API NF_STATUS NFAPI_CC 384 | nf_getTCPStat(ENDPOINT_ID id, PNF_FLOWCTL_STAT pStat); 385 | 386 | /** 387 | * Get UDP socket statistics as the numbers of in/out bytes. 388 | * The function can be called only from udpClosed handler! 389 | */ 390 | NFAPI_API NF_STATUS NFAPI_CC 391 | nf_getUDPStat(ENDPOINT_ID id, PNF_FLOWCTL_STAT pStat); 392 | 393 | /** 394 | * Add binding rule to driver 395 | */ 396 | NFAPI_API NF_STATUS NFAPI_CC 397 | nf_addBindingRule(PNF_BINDING_RULE pRule, int toHead); 398 | 399 | /** 400 | * Delete all binding rules from driver 401 | */ 402 | NFAPI_API NF_STATUS NFAPI_CC 403 | nf_deleteBindingRules(); 404 | 405 | /** 406 | * Returns the type of attached driver (DT_WFP, DT_TDI or DT_UNKNOWN) 407 | */ 408 | NFAPI_API unsigned long NFAPI_CC 409 | nf_getDriverType(); 410 | 411 | #ifdef __cplusplus 412 | } 413 | #endif 414 | 415 | #endif -------------------------------------------------------------------------------- /include/nfdriver_data.h: -------------------------------------------------------------------------------- 1 | // 2 | // NetFilterSDK 3 | // Copyright (C) Vitaly Sidorov 4 | // All rights reserved. 5 | // 6 | // This file is a part of the NetFilter SDK. 7 | // The code and information is provided "as-is" without 8 | // warranty of any kind, either expressed or implied. 9 | // 10 | 11 | 12 | #ifndef _NFDRIVER_DATA_H 13 | #define _NFDRIVER_DATA_H 14 | 15 | #define NF_TCP_PACKET_BUF_SIZE 8192 16 | #define NF_UDP_PACKET_BUF_SIZE 2 * 65536 17 | 18 | typedef enum _NF_DIRECTION 19 | { 20 | NF_D_IN = 1, // Incoming TCP connection or UDP packet 21 | NF_D_OUT = 2, // Outgoing TCP connection or UDP packet 22 | NF_D_BOTH = 3 // Any direction 23 | } NF_DIRECTION; 24 | 25 | typedef enum _NF_FILTERING_FLAG 26 | { 27 | NF_ALLOW = 0, // Allow the activity without filtering transmitted packets 28 | NF_BLOCK = 1, // Block the activity 29 | NF_FILTER = 2, // Filter the transmitted packets 30 | NF_SUSPENDED = 4, // Suspend receives from server and sends from client 31 | NF_OFFLINE = 8, // Emulate establishing a TCP connection with remote server 32 | NF_INDICATE_CONNECT_REQUESTS = 16, // Indicate outgoing connect requests to API 33 | NF_DISABLE_REDIRECT_PROTECTION = 32, // Disable blocking indicating connect requests for outgoing connections of local proxies 34 | NF_PEND_CONNECT_REQUEST = 64, // Pend outgoing connect request to complete it later using nf_complete(TCP|UDP)ConnectRequest 35 | NF_FILTER_AS_IP_PACKETS = 128, // Indicate the traffic as IP packets via ipSend/ipReceive 36 | NF_READONLY = 256, // Don't block the IP packets and indicate them to ipSend/ipReceive only for monitoring 37 | NF_CONTROL_FLOW = 512, // Use the flow limit rules even without NF_FILTER flag 38 | NF_REDIRECT = 1024, // Redirect the outgoing TCP connections to address specified in redirectTo 39 | NF_BYPASS_IP_PACKETS = 2048, // Bypass the traffic as IP packets, when used with NF_FILTER_AS_IP_PACKETS flag 40 | } NF_FILTERING_FLAG; 41 | 42 | #pragma pack(push, 1) 43 | 44 | #define NF_MAX_ADDRESS_LENGTH 28 45 | #define NF_MAX_IP_ADDRESS_LENGTH 16 46 | 47 | #ifndef AF_INET 48 | #define AF_INET 2 /* internetwork: UDP, TCP, etc. */ 49 | #endif 50 | 51 | #ifndef AF_INET6 52 | #define AF_INET6 23 /* Internetwork Version 6 */ 53 | #endif 54 | 55 | // Protocols 56 | 57 | #ifndef IPPROTO_TCP 58 | #define IPPROTO_TCP 6 59 | #endif 60 | 61 | #ifndef IPPROTO_UDP 62 | #define IPPROTO_UDP 17 63 | #endif 64 | 65 | /** 66 | * Filtering rule 67 | **/ 68 | typedef UNALIGNED struct _NF_RULE 69 | { 70 | int protocol; // IPPROTO_TCP or IPPROTO_UDP 71 | unsigned long processId; // Process identifier 72 | unsigned char direction; // See NF_DIRECTION 73 | unsigned short localPort; // Local port 74 | unsigned short remotePort; // Remote port 75 | unsigned short ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6 76 | 77 | // Local IP (or network if localIpAddressMask is not zero) 78 | unsigned char localIpAddress[NF_MAX_IP_ADDRESS_LENGTH]; 79 | 80 | // Local IP mask 81 | unsigned char localIpAddressMask[NF_MAX_IP_ADDRESS_LENGTH]; 82 | 83 | // Remote IP (or network if remoteIpAddressMask is not zero) 84 | unsigned char remoteIpAddress[NF_MAX_IP_ADDRESS_LENGTH]; 85 | 86 | // Remote IP mask 87 | unsigned char remoteIpAddressMask[NF_MAX_IP_ADDRESS_LENGTH]; 88 | 89 | unsigned long filteringFlag; // See NF_FILTERING_FLAG 90 | } NF_RULE, *PNF_RULE; 91 | 92 | 93 | typedef struct _NF_PORT_RANGE 94 | { 95 | unsigned short valueLow; 96 | unsigned short valueHigh; 97 | } NF_PORT_RANGE, *PNF_PORT_RANGE; 98 | 99 | 100 | /** 101 | * Filtering rule with additional fields 102 | **/ 103 | typedef UNALIGNED struct _NF_RULE_EX 104 | { 105 | int protocol; // IPPROTO_TCP or IPPROTO_UDP 106 | unsigned long processId; // Process identifier 107 | unsigned char direction; // See NF_DIRECTION 108 | unsigned short localPort; // Local port 109 | unsigned short remotePort; // Remote port 110 | unsigned short ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6 111 | 112 | // Local IP (or network if localIpAddressMask is not zero) 113 | unsigned char localIpAddress[NF_MAX_IP_ADDRESS_LENGTH]; 114 | 115 | // Local IP mask 116 | unsigned char localIpAddressMask[NF_MAX_IP_ADDRESS_LENGTH]; 117 | 118 | // Remote IP (or network if remoteIpAddressMask is not zero) 119 | unsigned char remoteIpAddress[NF_MAX_IP_ADDRESS_LENGTH]; 120 | 121 | // Remote IP mask 122 | unsigned char remoteIpAddressMask[NF_MAX_IP_ADDRESS_LENGTH]; 123 | 124 | unsigned long filteringFlag; // See NF_FILTERING_FLAG 125 | 126 | // Process name tail mask (supports * as 0 or more symbols) 127 | wchar_t processName[_MAX_PATH]; 128 | 129 | NF_PORT_RANGE localPortRange; // Local port(s) 130 | NF_PORT_RANGE remotePortRange; // Remote port(s) 131 | 132 | // Remote address for redirection as sockaddr_in for IPv4 and sockaddr_in6 for IPv6 133 | unsigned char redirectTo[NF_MAX_ADDRESS_LENGTH]; 134 | // Process identifier of a local proxy 135 | unsigned long localProxyProcessId; 136 | 137 | } NF_RULE_EX, *PNF_RULE_EX; 138 | 139 | typedef unsigned __int64 ENDPOINT_ID; 140 | 141 | 142 | /** 143 | * TCP connection properties 144 | **/ 145 | typedef UNALIGNED struct _NF_TCP_CONN_INFO 146 | { 147 | unsigned long filteringFlag; // See NF_FILTERING_FLAG 148 | unsigned long processId; // Process identifier 149 | unsigned char direction; // See NF_DIRECTION 150 | unsigned short ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6 151 | 152 | // Local address as sockaddr_in for IPv4 and sockaddr_in6 for IPv6 153 | unsigned char localAddress[NF_MAX_ADDRESS_LENGTH]; 154 | 155 | // Remote address as sockaddr_in for IPv4 and sockaddr_in6 for IPv6 156 | unsigned char remoteAddress[NF_MAX_ADDRESS_LENGTH]; 157 | 158 | } NF_TCP_CONN_INFO, *PNF_TCP_CONN_INFO; 159 | 160 | /** 161 | * UDP endpoint properties 162 | **/ 163 | typedef UNALIGNED struct _NF_UDP_CONN_INFO 164 | { 165 | unsigned long processId; // Process identifier 166 | unsigned short ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6 167 | 168 | // Local address as sockaddr_in for IPv4 and sockaddr_in6 for IPv6 169 | unsigned char localAddress[NF_MAX_ADDRESS_LENGTH]; 170 | 171 | } NF_UDP_CONN_INFO, *PNF_UDP_CONN_INFO; 172 | 173 | /** 174 | * UDP TDI_CONNECT request properties 175 | **/ 176 | typedef UNALIGNED struct _NF_UDP_CONN_REQUEST 177 | { 178 | unsigned long filteringFlag; // See NF_FILTERING_FLAG 179 | unsigned long processId; // Process identifier 180 | unsigned short ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6 181 | 182 | // Local address as sockaddr_in for IPv4 and sockaddr_in6 for IPv6 183 | unsigned char localAddress[NF_MAX_ADDRESS_LENGTH]; 184 | 185 | // Remote address as sockaddr_in for IPv4 and sockaddr_in6 for IPv6 186 | unsigned char remoteAddress[NF_MAX_ADDRESS_LENGTH]; 187 | 188 | } NF_UDP_CONN_REQUEST, *PNF_UDP_CONN_REQUEST; 189 | 190 | /** 191 | * UDP options 192 | **/ 193 | typedef UNALIGNED struct _NF_UDP_OPTIONS 194 | { 195 | unsigned long flags; // Datagram flags 196 | long optionsLength; // Length of options buffer 197 | unsigned char options[1]; // Options of variable size 198 | } NF_UDP_OPTIONS, *PNF_UDP_OPTIONS; 199 | 200 | typedef enum _NF_IP_FLAG 201 | { 202 | NFIF_NONE = 0, // No flags 203 | NFIF_READONLY = 1, // The packet was not blocked and indicated only for monitoring in read-only mode 204 | // (see NF_READ_ONLY flags from NF_FILTERING_FLAG). 205 | } NF_IP_FLAG; 206 | 207 | /** 208 | * IP options 209 | **/ 210 | typedef struct _NF_IP_PACKET_OPTIONS 211 | { 212 | unsigned short ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6 213 | unsigned int ipHeaderSize; // Size in bytes of IP header 214 | unsigned long compartmentId; // Network routing compartment identifier (can be zero) 215 | unsigned long interfaceIndex; // Index of the interface on which the original packet data was received (irrelevant to outgoing packets) 216 | unsigned long subInterfaceIndex; // Index of the subinterface on which the original packet data was received (irrelevant to outgoing packets) 217 | unsigned long flags; // Can be a combination of flags from NF_IP_FLAG enumeration 218 | } NF_IP_PACKET_OPTIONS, *PNF_IP_PACKET_OPTIONS; 219 | 220 | /** 221 | * Internal IO structure 222 | **/ 223 | typedef UNALIGNED struct _NF_DATA 224 | { 225 | int code; 226 | ENDPOINT_ID id; 227 | unsigned long bufferSize; 228 | char buffer[1]; 229 | } NF_DATA, *PNF_DATA; 230 | 231 | typedef UNALIGNED struct _NF_BUFFERS 232 | { 233 | unsigned __int64 inBuf; 234 | unsigned __int64 inBufLen; 235 | unsigned __int64 outBuf; 236 | unsigned __int64 outBufLen; 237 | } NF_BUFFERS, *PNF_BUFFERS; 238 | 239 | typedef UNALIGNED struct _NF_READ_RESULT 240 | { 241 | unsigned __int64 length; 242 | } NF_READ_RESULT, *PNF_READ_RESULT; 243 | 244 | typedef UNALIGNED struct _NF_FLOWCTL_DATA 245 | { 246 | unsigned __int64 inLimit; 247 | unsigned __int64 outLimit; 248 | } NF_FLOWCTL_DATA, *PNF_FLOWCTL_DATA; 249 | 250 | typedef UNALIGNED struct _NF_FLOWCTL_MODIFY_DATA 251 | { 252 | unsigned int fcHandle; 253 | NF_FLOWCTL_DATA data; 254 | } NF_FLOWCTL_MODIFY_DATA, *PNF_FLOWCTL_MODIFY_DATA; 255 | 256 | typedef UNALIGNED struct _NF_FLOWCTL_STAT 257 | { 258 | unsigned __int64 inBytes; 259 | unsigned __int64 outBytes; 260 | } NF_FLOWCTL_STAT, *PNF_FLOWCTL_STAT; 261 | 262 | typedef UNALIGNED struct _NF_FLOWCTL_SET_DATA 263 | { 264 | unsigned __int64 endpointId; 265 | unsigned int fcHandle; 266 | } NF_FLOWCTL_SET_DATA, *PNF_FLOWCTL_SET_DATA; 267 | 268 | 269 | /** 270 | * Binding rule 271 | **/ 272 | typedef UNALIGNED struct _NF_BINDING_RULE 273 | { 274 | int protocol; // IPPROTO_TCP or IPPROTO_UDP 275 | 276 | unsigned long processId; // Process identifier 277 | 278 | // Process name tail mask (supports * as 0 or more symbols) 279 | wchar_t processName[_MAX_PATH]; 280 | 281 | unsigned short localPort; // Local port 282 | 283 | unsigned short ip_family; // AF_INET for IPv4 and AF_INET6 for IPv6 284 | 285 | // Local IP (or network if localIpAddressMask is not zero) 286 | unsigned char localIpAddress[NF_MAX_IP_ADDRESS_LENGTH]; 287 | 288 | // Local IP mask 289 | unsigned char localIpAddressMask[NF_MAX_IP_ADDRESS_LENGTH]; 290 | 291 | // Redirect bind request to this IP 292 | unsigned char newLocalIpAddress[NF_MAX_IP_ADDRESS_LENGTH]; 293 | 294 | // Redirect bind request to this port, if it is not zero 295 | unsigned short newLocalPort; 296 | 297 | unsigned long filteringFlag; // See NF_FILTERING_FLAG, NF_ALLOW or NF_FILTER 298 | 299 | } NF_BINDING_RULE, *PNF_BINDING_RULE; 300 | 301 | 302 | #pragma pack(pop) 303 | 304 | #ifdef WIN32 305 | 306 | typedef enum _NF_DRIVER_TYPE 307 | { 308 | DT_UNKNOWN = 0, 309 | DT_TDI = 1, 310 | DT_WFP = 2, 311 | DT_SOCK = 3, 312 | } NF_DRIVER_TYPE; 313 | 314 | #endif 315 | 316 | #endif // _NFDRIVER_DATA_H -------------------------------------------------------------------------------- /include/nfevents.h: -------------------------------------------------------------------------------- 1 | // 2 | // NetFilterSDK 3 | // Copyright (C) Vitaly Sidorov 4 | // All rights reserved. 5 | // 6 | // This file is a part of the NetFilter SDK. 7 | // The code and information is provided "as-is" without 8 | // warranty of any kind, either expressed or implied. 9 | // 10 | 11 | 12 | #ifndef _NFEVENTS_H 13 | #define _NFEVENTS_H 14 | 15 | /** 16 | * Return status codes 17 | **/ 18 | typedef enum _NF_STATUS 19 | { 20 | NF_STATUS_SUCCESS = 0, 21 | NF_STATUS_FAIL = -1, 22 | NF_STATUS_INVALID_ENDPOINT_ID = -2, 23 | NF_STATUS_NOT_INITIALIZED = -3, 24 | NF_STATUS_IO_ERROR = -4, 25 | NF_STATUS_REBOOT_REQUIRED = -5 26 | } NF_STATUS; 27 | 28 | #ifndef _C_API 29 | 30 | #define NFAPI_NS nfapi:: 31 | #define NFAPI_CC 32 | 33 | ///////////////////////////////////////////////////////////////////////////////////// 34 | // C++ API 35 | ///////////////////////////////////////////////////////////////////////////////////// 36 | 37 | namespace nfapi 38 | { 39 | #include "nfdriver_data.h" 40 | 41 | /** 42 | * Filtering events 43 | **/ 44 | class NF_EventHandler 45 | { 46 | public: 47 | 48 | /** 49 | * Called immediately after starting the filtering thread. 50 | * Use this event for thread-specific initialization, e.g. calling 51 | * CoInitialize() etc. 52 | **/ 53 | virtual void threadStart() = 0; 54 | 55 | /** 56 | * Called before stopping the thread. 57 | **/ 58 | virtual void threadEnd() = 0; 59 | 60 | // 61 | // TCP events 62 | // 63 | 64 | /** 65 | * Called before establishing an outgoing TCP connection, 66 | * when NF_INDICATE_CONNECT_REQUESTS flag is specified in an appropriate rule. 67 | * It is possible to change pConnInfo->filteringFlag and pConnInfo->remoteAddress 68 | * in this handler. The changes will be applied to connection. 69 | * @param id Unique connection identifier 70 | * @param pConnInfo Connection parameters, see NF_TCP_CONN_INFO 71 | **/ 72 | virtual void tcpConnectRequest(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo) = 0; 73 | 74 | /** 75 | * Called after successful establishing the incoming or outgoing TCP connection. 76 | * @param id Unique connection identifier 77 | * @param pConnInfo Connection parameters, see NF_TCP_CONN_INFO 78 | **/ 79 | virtual void tcpConnected(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo) = 0; 80 | 81 | /** 82 | * Called after closing the connection identified by id. 83 | * @param id Unique connection identifier 84 | * @param pConnInfo Connection parameters, see NF_TCP_CONN_INFO 85 | **/ 86 | virtual void tcpClosed(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo) = 0; 87 | 88 | /** 89 | * Indicates the buffer received from server. 90 | * @param id Unique connection identifier 91 | * @param buf Pointer to data buffer 92 | * @param len Buffer length 93 | **/ 94 | virtual void tcpReceive(ENDPOINT_ID id, const char * buf, int len) = 0; 95 | 96 | /** 97 | * Indicates the buffer sent from the local socket. 98 | * @param id Unique connection identifier 99 | * @param buf Pointer to data buffer 100 | * @param len Buffer length 101 | **/ 102 | virtual void tcpSend(ENDPOINT_ID id, const char * buf, int len) = 0; 103 | 104 | /** 105 | * Informs that the internal buffer for receives is empty and 106 | * it is possible to call nf_tcpPostReceive for pushing receives 107 | * via specified connection. 108 | * @param id Unique connection identifier 109 | **/ 110 | virtual void tcpCanReceive(ENDPOINT_ID id) = 0; 111 | 112 | /** 113 | * Informs that the internal buffer for sends is empty and 114 | * it is possible to call nf_tcpPostSend for pushing sends 115 | * via specified connection. 116 | * @param id Unique connection identifier 117 | **/ 118 | virtual void tcpCanSend(ENDPOINT_ID id) = 0; 119 | 120 | 121 | // 122 | // UDP events 123 | // 124 | 125 | /** 126 | * Called after creating UDP socket. 127 | * @param id Unique socket identifier 128 | * @param pConnInfo Socket parameters, see NF_UDP_CONN_INFO 129 | **/ 130 | virtual void udpCreated(ENDPOINT_ID id, PNF_UDP_CONN_INFO pConnInfo) = 0; 131 | 132 | /** 133 | * Called before establishing an outgoing UDP connection, 134 | * when NF_INDICATE_CONNECT_REQUESTS flag is specified in an appropriate rule. 135 | * It is possible to change pConnReq->filteringFlag and pConnReq->remoteAddress 136 | * in this handler. The changes will be applied to connection. 137 | * @param id Unique connection identifier 138 | * @param pConnInfo Connection parameters, see NF_UDP_CONN_REQUEST 139 | **/ 140 | virtual void udpConnectRequest(ENDPOINT_ID id, PNF_UDP_CONN_REQUEST pConnReq) = 0; 141 | 142 | /** 143 | * Called after closing UDP socket identified by id. 144 | * @param id Unique socket identifier 145 | * @param pConnInfo Socket parameters, see NF_UDP_CONN_INFO 146 | **/ 147 | virtual void udpClosed(ENDPOINT_ID id, PNF_UDP_CONN_INFO pConnInfo) = 0; 148 | 149 | /** 150 | * Indicates the buffer received from server. 151 | * @param id Unique socket identifier 152 | * @param options UDP options 153 | * @param remoteAddress Source address 154 | * @param buf Pointer to data buffer 155 | * @param len Buffer length 156 | **/ 157 | virtual void udpReceive(ENDPOINT_ID id, const unsigned char * remoteAddress, const char * buf, int len, PNF_UDP_OPTIONS options) = 0; 158 | 159 | /** 160 | * Indicates the buffer sent from the local socket. 161 | * @param id Unique socket identifier 162 | * @param options UDP options 163 | * @param remoteAddress Destination address 164 | * @param buf Pointer to data buffer 165 | * @param len Buffer length 166 | **/ 167 | virtual void udpSend(ENDPOINT_ID id, const unsigned char * remoteAddress, const char * buf, int len, PNF_UDP_OPTIONS options) = 0; 168 | 169 | /** 170 | * Informs that the internal buffer for receives is empty and 171 | * it is possible to call nf_udpPostReceive for pushing receives 172 | * via specified socket. 173 | * @param id Unique socket identifier 174 | **/ 175 | virtual void udpCanReceive(ENDPOINT_ID id) = 0; 176 | 177 | /** 178 | * Informs that the internal buffer for sends is empty and 179 | * it is possible to call nf_udpPostSend for pushing sends 180 | * via specified socket. 181 | * @param id Unique socket identifier 182 | **/ 183 | virtual void udpCanSend(ENDPOINT_ID id) = 0; 184 | }; 185 | 186 | /** 187 | * IP level filtering events 188 | **/ 189 | class NF_IPEventHandler 190 | { 191 | public: 192 | /** 193 | * Indicates a packet received from server. 194 | * @param buf Pointer to data buffer 195 | * @param len Buffer length 196 | * @param options IP options 197 | **/ 198 | virtual void ipReceive(const char * buf, int len, PNF_IP_PACKET_OPTIONS options) = 0; 199 | 200 | /** 201 | * Indicates a packet sent to server. 202 | * @param buf Pointer to data buffer 203 | * @param len Buffer length 204 | * @param options IP options 205 | **/ 206 | virtual void ipSend(const char * buf, int len, PNF_IP_PACKET_OPTIONS options) = 0; 207 | }; 208 | 209 | #else 210 | 211 | #ifdef WIN32 212 | #define NFAPI_CC __cdecl 213 | #else 214 | #define NFAPI_CC 215 | #endif 216 | #define NFAPI_NS 217 | 218 | ///////////////////////////////////////////////////////////////////////////////////// 219 | // C API 220 | ///////////////////////////////////////////////////////////////////////////////////// 221 | 222 | #ifdef __cplusplus 223 | extern "C" 224 | { 225 | #endif 226 | 227 | #include "nfdriver_data.h" 228 | 229 | #pragma pack(push, 1) 230 | 231 | // C analogue of the class NF_EventHandler (see the definition above) 232 | typedef struct _NF_EventHandler 233 | { 234 | void (NFAPI_CC *threadStart)(); 235 | void (NFAPI_CC *threadEnd)(); 236 | void (NFAPI_CC *tcpConnectRequest)(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo); 237 | void (NFAPI_CC *tcpConnected)(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo); 238 | void (NFAPI_CC *tcpClosed)(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo); 239 | void (NFAPI_CC *tcpReceive)(ENDPOINT_ID id, const char * buf, int len); 240 | void (NFAPI_CC *tcpSend)(ENDPOINT_ID id, const char * buf, int len); 241 | void (NFAPI_CC *tcpCanReceive)(ENDPOINT_ID id); 242 | void (NFAPI_CC *tcpCanSend)(ENDPOINT_ID id); 243 | void (NFAPI_CC *udpCreated)(ENDPOINT_ID id, PNF_UDP_CONN_INFO pConnInfo); 244 | void (NFAPI_CC *udpConnectRequest)(ENDPOINT_ID id, PNF_UDP_CONN_REQUEST pConnReq); 245 | void (NFAPI_CC *udpClosed)(ENDPOINT_ID id, PNF_UDP_CONN_INFO pConnInfo); 246 | void (NFAPI_CC *udpReceive)(ENDPOINT_ID id, const unsigned char * remoteAddress, const char * buf, int len, PNF_UDP_OPTIONS options); 247 | void (NFAPI_CC *udpSend)(ENDPOINT_ID id, const unsigned char * remoteAddress, const char * buf, int len, PNF_UDP_OPTIONS options); 248 | void (NFAPI_CC *udpCanReceive)(ENDPOINT_ID id); 249 | void (NFAPI_CC *udpCanSend)(ENDPOINT_ID id); 250 | } NF_EventHandler, *PNF_EventHandler; 251 | 252 | // C analogue of the class NF_IPEventHandler (see the definition above) 253 | typedef struct _NF_IPEventHandler 254 | { 255 | void (NFAPI_CC *ipReceive)(const char * buf, int len, PNF_IP_PACKET_OPTIONS options); 256 | void (NFAPI_CC *ipSend)(const char * buf, int len, PNF_IP_PACKET_OPTIONS options); 257 | } NF_IPEventHandler, *PNF_IPEventHandler; 258 | 259 | #pragma pack(pop) 260 | 261 | #endif 262 | 263 | 264 | #ifdef __cplusplus 265 | } 266 | #endif 267 | 268 | #endif -------------------------------------------------------------------------------- /include/samples_config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Driver name for using in samples 4 | #define NFDRIVER_NAME "netfilter2" 5 | -------------------------------------------------------------------------------- /lib/release/win32/nfapi.exp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dyhkwong/SocksRedirector/7489085ca4f960f4a54f89346f2e2306212eb220/lib/release/win32/nfapi.exp -------------------------------------------------------------------------------- /lib/release/win32/nfapi.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dyhkwong/SocksRedirector/7489085ca4f960f4a54f89346f2e2306212eb220/lib/release/win32/nfapi.lib -------------------------------------------------------------------------------- /lib/release/x64/nfapi.exp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dyhkwong/SocksRedirector/7489085ca4f960f4a54f89346f2e2306212eb220/lib/release/x64/nfapi.exp -------------------------------------------------------------------------------- /lib/release/x64/nfapi.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dyhkwong/SocksRedirector/7489085ca4f960f4a54f89346f2e2306212eb220/lib/release/x64/nfapi.lib -------------------------------------------------------------------------------- /license.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1251\uc1\deff0\stshfdbch0\stshfloch0\stshfhich0\stshfbi0\deflang1049\deflangfe1049{\fonttbl{\f0\froman\fcharset204\fprq2{\*\panose 02020603050405020304}Times New Roman;} 2 | {\f37\fswiss\fcharset204\fprq2{\*\panose 020b0604020202020204}Arial CYR;}{\f57\froman\fcharset0\fprq2 Times New Roman;}{\f55\froman\fcharset238\fprq2 Times New Roman CE;}{\f58\froman\fcharset161\fprq2 Times New Roman Greek;} 3 | {\f59\froman\fcharset162\fprq2 Times New Roman Tur;}{\f60\froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f61\froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f62\froman\fcharset186\fprq2 Times New Roman Baltic;} 4 | {\f63\froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f427\fswiss\fcharset0\fprq2 Arial CYR;}{\f425\fswiss\fcharset238\fprq2 Arial CYR CE;}{\f428\fswiss\fcharset161\fprq2 Arial CYR Greek;}{\f429\fswiss\fcharset162\fprq2 Arial CYR Tur;} 5 | {\f430\fswiss\fcharset177\fprq2 Arial CYR (Hebrew);}{\f431\fswiss\fcharset178\fprq2 Arial CYR (Arabic);}{\f432\fswiss\fcharset186\fprq2 Arial CYR Baltic;}{\f433\fswiss\fcharset163\fprq2 Arial CYR (Vietnamese);}}{\colortbl;\red0\green0\blue0; 6 | \red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128; 7 | \red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}{\stylesheet{\ql \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \fs24\lang1049\langfe1049\cgrid\langnp1049\langfenp1049 \snext0 Normal;} 8 | {\*\cs10 \additive \ssemihidden Default Paragraph Font;}{\* 9 | \ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tscellwidthfts0\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv 10 | \ql \li0\ri0\widctlpar\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \fs20\lang1024\langfe1024\cgrid\langnp1024\langfenp1024 \snext11 \ssemihidden Normal Table;}}{\*\latentstyles\lsdstimax156\lsdlockeddef0}{\*\rsidtbl \rsid8089115\rsid13644200 11 | \rsid14500568\rsid15738103}{\*\generator Microsoft Word 11.0.5604;}{\info{\author vetal}{\operator vetal}{\creatim\yr2009\mo8\dy11\hr9\min18}{\revtim\yr2009\mo8\dy12\hr6\min58}{\version4}{\edmins3}{\nofpages2}{\nofwords587}{\nofchars3347}{\*\company gv} 12 | {\nofcharsws3927}{\vern24689}}\margl1701\margr850\margt1134\margb1134 \widowctrl\ftnbj\aenddoc\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\hyphcaps0\horzdoc\dghspace120\dgvspace120\dghorigin1701\dgvorigin1984\dghshow0\dgvshow3 13 | \jcompress\viewkind4\viewscale100\nolnhtadjtbl\rsidroot8089115 \fet0\sectd \linex0\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl3 14 | \pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}} 15 | {\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}\pard\plain 16 | \ql \li0\ri0\nowidctlpar\faauto\rin0\lin0\itap0 \fs24\lang1049\langfe1049\cgrid\langnp1049\langfenp1049 {\b\f37\fs20\lang1033\langfe1049\langnp1033\insrsid13644200\charrsid8089115 LICENSE STATEMENT 17 | \par }{\f37\fs20\lang1033\langfe1049\langnp1033\insrsid13644200\charrsid8089115 18 | \par All copyrights to NetFilter SDK are exclusively owned by the author - Vitaly Sidorov 19 | \par 20 | \par }{\b\f37\fs20\insrsid13644200 Using NetFilter SDK}{\f37\fs20\insrsid13644200 21 | \par 22 | \par }{\f37\fs20\lang1033\langfe1049\langnp1033\insrsid13644200\charrsid8089115 The sources provided as part of the NetFilter SDK product are intended to be incorporated into your own programs. }{ 23 | \f37\fs20\lang1033\langfe1049\langnp1033\insrsid8089115\charrsid15738103 You may modify the source code of the }{\f37\fs20\lang1033\langfe1049\langnp1033\insrsid8089115 NetFilter SDK}{ 24 | \f37\fs20\lang1033\langfe1049\langnp1033\insrsid8089115\charrsid15738103 to adapt it to your needs.}{\f37\fs20\lang1033\langfe1049\langnp1033\insrsid8089115 }{\f37\fs20\lang1033\langfe1049\langnp1033\insrsid13644200\charrsid8089115 25 | Nevertheless, the original NetFilter SDK sou}{\f37\fs20\lang1033\langfe1049\langnp1033\insrsid8089115 r}{\f37\fs20\lang1033\langfe1049\langnp1033\insrsid13644200\charrsid8089115 ces, samples and documentation are the property of author a 26 | nd author provides you with only specific and limited rights to their use. }{\f37\fs20\lang1033\langfe1049\langnp1033\insrsid14500568 Subject to the foregoing rights of the author and subject to the paragraph below entitled \'93Distribution in Source Form 27 | \'94, you may own the source code modified by you. }{\f37\fs20\lang1033\langfe1049\langnp1033\insrsid13644200\charrsid8089115 Any rights not specifically granted in this statement are reserved by author. 28 | \par 29 | \par }{\b\f37\fs20\lang1033\langfe1049\langnp1033\insrsid13644200\charrsid8089115 Distribution In Executable Form 30 | \par }{\f37\fs20\lang1033\langfe1049\langnp1033\insrsid13644200\charrsid8089115 31 | \par }\pard \ql \li0\ri0\nowidctlpar\faauto\rin0\lin0\itap0\pararsid8089115 {\f37\fs20\lang1033\langfe1049\langnp1033\insrsid8089115\charrsid15738103 Author grants you the right to }{\f37\fs20\lang1033\langfe1049\langnp1033\insrsid8089115 copy}{ 32 | \f37\fs20\lang1033\langfe1049\langnp1033\insrsid8089115\charrsid15738103 the NetFilter SDK }{\f37\fs20\lang1033\langfe1049\langnp1033\insrsid8089115 and incorporate it }{\f37\fs20\lang1033\langfe1049\langnp1033\insrsid8089115\charrsid15738103 33 | into your own programs as long as your program adds substantial functionality beyond that provided in the original sources. You may distribute programs that you create and which contain elements of the original NetFilter SDK, in executable form only, 34 | without restriction or fee provided that all copies of your programs bear a valid copyright notice. By \'93copyright notice\'94 35 | , we mean your own copyright notice. You, of course, shall remain solely responsible for, and will hold author harmless from, all claims, liability and damages arising from your own products which may include elements of the NetFilter SDK code. }{ 36 | \f37\fs20\lang1033\langfe1049\langnp1033\insrsid8089115 The right of users to use the program into which the NetFilter SDK has been incorporated is perpetual even if this License Statement is terminated.}{ 37 | \f37\fs20\lang1033\langfe1049\langnp1033\insrsid8089115\charrsid15738103 38 | \par }\pard \ql \li0\ri0\nowidctlpar\faauto\rin0\lin0\itap0 {\f37\fs20\lang1033\langfe1049\langnp1033\insrsid13644200\charrsid8089115 39 | \par }{\b\f37\fs20\lang1033\langfe1049\langnp1033\insrsid13644200\charrsid8089115 Distribution In Source Form}{\f37\fs20\lang1033\langfe1049\langnp1033\insrsid13644200\charrsid8089115 40 | \par 41 | \par Author does not grant you the right to give away, sell, license or otherwise distribute source code derived substantially from the NetFilter SDK unless the recipient of your source code obtains their own license to the NetFi 42 | lter SDK, identical to this license and at the same cost that you paid for this license. 43 | \par 44 | \par }{\b\f37\fs20\lang1033\langfe1049\langnp1033\insrsid13644200\charrsid8089115 LIMITED WARRANTY}{\f37\fs20\lang1033\langfe1049\langnp1033\insrsid13644200\charrsid8089115 45 | \par 46 | \par }{\b\f37\fs20\lang1033\langfe1049\langnp1033\insrsid13644200\charrsid8089115 Warranty Disclaimer 47 | \par }{\f37\fs20\lang1033\langfe1049\langnp1033\insrsid13644200\charrsid8089115 48 | \par AUTHOR SHALL PROVIDE THE SOFTWARE TO YOU WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES OF ANY KIND, INCLUDING, BUT NOT LIMITED TO, 49 | ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. AUTHOR MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND WITH RESPECT TO ANY SUPPORT SERVICES IT MAY RENDER TO YOU. AUTHOR DOES NOT WARRANT THAT THE SOFTWARE WILL MEET YOUR R 50 | EQUIREMENTS OR THAT THE OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR\_ 51 | FREE OR THAT THE SOFTWARE CONTAINS NO DEFECTS OR ERRORS. YOU ASSUME FULL RESPONSIBILITY FOR THE SELECTION, POSSESSION, PERFORMANCE AND PROPER INSTALLATION AND USE OF THE SOFTWARE AND FOR VERIFYING THE RESULTS OBTAINED THEREFROM. 52 | \par 53 | \par }{\b\f37\fs20\lang1033\langfe1049\langnp1033\insrsid13644200\charrsid8089115 Damage Disclaimer}{\f37\fs20\lang1033\langfe1049\langnp1033\insrsid13644200\charrsid8089115 54 | \par 55 | \par THE LIABILITY OF AUTHOR, SUCCESSORS OR ASSIGNS FOR DAMAGES, WHETHER FOR BREACH OF THIS LICENSE AND LIMITED WARRANTY OR OTHERWISE SHALL NOT EXCEED THE AMOUNT OF THE LICENSE FEE, WHETHER THE LIABILITY ARISES FROM CONTRACT, TORT OR OTHER CLAIMS. AUTHOR SPECI 56 | F 57 | ICALLY DISCLAIMS ANY INCIDENTAL, CONSEQUENTIAL OR SPECIAL DAMAGES WHICH MAY ARISE FROM THIS LICENSE AND LIMITED WARRANTY OR THE POSSESSION OR USE OF ALL OR ANY PORTION OF THE SOFTWARE, EVEN TO THE EXTENT AUTHOR IS AWARE OF THE RISK OF SUCH DAMAGES. AUTHOR 58 | SHALL NOT BE LIABLE FOR COSTS OR PROCUREMENT OF SUBSTITUTE PRODUCTS NOR FOR ANY LOST PROFITS, LOST BUSINESS, LOSS OF USE OR DATA OR INTERRUPTION OF BUSINESS ARISING OUT OF ANY USE OR FAILURE OF ALL OR ANY PORTION OF THE SOFTWARE 59 | \par 60 | \par }{\b\f37\fs20\lang1033\langfe1049\langnp1033\insrsid13644200\charrsid8089115 Amendments 61 | \par }{\f37\fs20\lang1033\langfe1049\langnp1033\insrsid13644200\charrsid8089115 62 | \par No amendment, 63 | change, or modification of this License and Limited Warranty or any of the terms, conditions or provisions hereof, and no waiver of a right, remedy, privilege or power, or discharge of an obligation or liability, conferred upon, vested in, or imposed upo 64 | n either Party, and no consent to any act or omission pertaining hereto shall be effective unless duly embodied in a written instrument signed by the duly authorized representatives of both Parties. 65 | \par }} -------------------------------------------------------------------------------- /src/SocksRedirector.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * This sample redirects TCP/UDP traffic to the specified SOCKS5 proxy. 3 | **/ 4 | 5 | #include "stdafx.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "nfapi.h" 12 | #include "sync.h" 13 | #include "icmp.h" 14 | #include "UdpProxy.h" 15 | #include "TcpProxy.h" 16 | #include "utf8.h" 17 | #include "samples_config.h" 18 | 19 | using namespace nfapi; 20 | 21 | #if defined(_DEBUG) || defined(_RELEASE_LOG) 22 | DBGLogger DBGLogger::dbgLog; 23 | #endif 24 | 25 | typedef std::vector tStrings; 26 | 27 | unsigned char g_proxyAddress[NF_MAX_ADDRESS_LENGTH]; 28 | unsigned char g_dnsAddress[NF_MAX_ADDRESS_LENGTH]; 29 | tStrings g_processNamesAllow; 30 | tStrings g_processNamesFilter; 31 | std::string g_userName; 32 | std::string g_userPassword; 33 | 34 | bool redirectDns; 35 | bool replyIcmp; 36 | 37 | inline bool safe_iswhitespace(int c) { return (c == (int) ' ' || c == (int) '\t' || c == (int) '\r' || c == (int) '\n'); } 38 | 39 | std::string trimWhitespace(std::string str) 40 | { 41 | while (str.length() > 0 && safe_iswhitespace(str[0])) 42 | { 43 | str.erase(0, 1); 44 | } 45 | 46 | while (str.length() > 0 && safe_iswhitespace(str[str.length()-1])) 47 | { 48 | str.erase(str.length()-1, 1); 49 | } 50 | 51 | return str; 52 | } 53 | 54 | bool parseValue(const std::string & _s, tStrings & v) 55 | { 56 | std::string sPart; 57 | size_t pos; 58 | std::string s = _s; 59 | 60 | v.clear(); 61 | 62 | while (!s.empty()) 63 | { 64 | pos = s.find(","); 65 | 66 | if (pos == std::string::npos) 67 | { 68 | sPart = trimWhitespace(s); 69 | s.erase(); 70 | } else 71 | { 72 | sPart = trimWhitespace(s.substr(0, pos)); 73 | s.erase(0, pos+1); 74 | } 75 | 76 | if (!sPart.empty()) 77 | { 78 | v.push_back(sPart); 79 | } 80 | } 81 | 82 | return true; 83 | } 84 | 85 | 86 | static std::string getProcessName(DWORD processId) 87 | { 88 | wchar_t processName[512] = L""; 89 | wchar_t fullProcessName[512] = L""; 90 | BOOL nameAcquired = FALSE; 91 | 92 | if (processId == 4) 93 | { 94 | return "system"; 95 | } 96 | 97 | nameAcquired = nf_getProcessNameFromKernel(processId, processName, sizeof(processName)/2); 98 | 99 | if (nameAcquired) 100 | { 101 | if (!GetLongPathNameW(processName, 102 | fullProcessName, 103 | (DWORD)ARRAYSIZE(fullProcessName))) 104 | { 105 | wcscpy(fullProcessName, processName); 106 | } 107 | } 108 | 109 | return encodeUTF8(fullProcessName); 110 | } 111 | 112 | bool checkProcessNameInAllow(DWORD processId) 113 | { 114 | std::string processName = getProcessName(processId); 115 | 116 | size_t processNameLen = processName.length(); 117 | 118 | for (size_t i=0; i processNameLen) 121 | continue; 122 | 123 | if (stricmp(g_processNamesAllow[i].c_str(), processName.c_str() + processNameLen - g_processNamesAllow[i].length()) == 0) 124 | return true; 125 | } 126 | 127 | return false; 128 | } 129 | 130 | bool checkProcessNameInFilter(DWORD processId) 131 | { 132 | std::string processName = getProcessName(processId); 133 | 134 | size_t processNameLen = processName.length(); 135 | 136 | for (size_t i=0; i processNameLen) 139 | continue; 140 | 141 | if (stricmp(g_processNamesFilter[i].c_str(), processName.c_str() + processNameLen - g_processNamesFilter[i].length()) == 0) 142 | return true; 143 | } 144 | 145 | return false; 146 | } 147 | 148 | struct DNS_REQUEST 149 | { 150 | DNS_REQUEST(ENDPOINT_ID id, const unsigned char * remoteAddress, const char * buf, int len, PNF_UDP_OPTIONS options) 151 | { 152 | m_id = id; 153 | 154 | memcpy(m_remoteAddress, remoteAddress, NF_MAX_ADDRESS_LENGTH); 155 | 156 | if (buf) 157 | { 158 | m_buf = new char[len]; 159 | memcpy(m_buf, buf, len); 160 | m_len = len; 161 | } else 162 | { 163 | m_buf = NULL; 164 | len = 0; 165 | } 166 | 167 | if (options) 168 | { 169 | m_options = (PNF_UDP_OPTIONS)new char[sizeof(NF_UDP_OPTIONS) + options->optionsLength]; 170 | memcpy(m_options, options, sizeof(NF_UDP_OPTIONS) + options->optionsLength - 1); 171 | } else 172 | { 173 | m_options = NULL; 174 | } 175 | } 176 | 177 | ~DNS_REQUEST() 178 | { 179 | if (m_buf) 180 | delete[] m_buf; 181 | if (m_options) 182 | delete[] m_options; 183 | } 184 | 185 | ENDPOINT_ID m_id; 186 | unsigned char m_remoteAddress[NF_MAX_ADDRESS_LENGTH]; 187 | char * m_buf; 188 | int m_len; 189 | PNF_UDP_OPTIONS m_options; 190 | }; 191 | 192 | class DnsResolver 193 | { 194 | public: 195 | DnsResolver() 196 | { 197 | m_stopEvent.Attach(CreateEvent(NULL, TRUE, FALSE, NULL)); 198 | } 199 | 200 | ~DnsResolver() 201 | { 202 | free(); 203 | } 204 | 205 | bool init(int threadCount) 206 | { 207 | HANDLE hThread; 208 | unsigned threadId; 209 | int i; 210 | 211 | ResetEvent(m_stopEvent); 212 | 213 | if (threadCount <= 0) 214 | { 215 | SYSTEM_INFO sysinfo; 216 | GetSystemInfo( &sysinfo ); 217 | 218 | threadCount = sysinfo.dwNumberOfProcessors; 219 | if (threadCount == 0) 220 | { 221 | threadCount = 1; 222 | } 223 | } 224 | 225 | for (i=0; isa_family == AF_INET6)? sizeof(sockaddr_in6) : sizeof(sockaddr_in); 277 | 278 | printf("DnsResolver::handleRequest() id=%I64u\n", pRequest->m_id); 279 | 280 | len = sendto(s, pRequest->m_buf, pRequest->m_len, 0, (sockaddr*)&g_dnsAddress, size); 281 | if (len != SOCKET_ERROR) 282 | { 283 | fd_set fdr, fde; 284 | timeval tv; 285 | 286 | FD_ZERO(&fdr); 287 | FD_SET(s, &fdr); 288 | FD_ZERO(&fde); 289 | FD_SET(s, &fde); 290 | 291 | tv.tv_sec = 2; 292 | tv.tv_usec = 0; 293 | 294 | len = select(1, &fdr, NULL, &fde, &tv); 295 | if (len != SOCKET_ERROR) 296 | { 297 | if (FD_ISSET(s, &fdr)) 298 | { 299 | char result[1024]; 300 | int fromLen; 301 | 302 | fromLen = size; 303 | len = recvfrom(s, result, (int)sizeof(result), 0, (sockaddr*)&g_dnsAddress, &fromLen); 304 | if (len != SOCKET_ERROR) 305 | { 306 | nf_udpPostReceive(pRequest->m_id, 307 | pRequest->m_remoteAddress, 308 | result, 309 | len, 310 | pRequest->m_options); 311 | 312 | printf("DnsResolver::handleRequest() id=%I64u succeeded, len=%d\n", pRequest->m_id, len); 313 | } else 314 | { 315 | printf("DnsResolver::handleRequest() id=%I64u recvfrom error=%d\n", pRequest->m_id, GetLastError()); 316 | } 317 | } else 318 | { 319 | printf("DnsResolver::handleRequest() id=%I64u no data\n", pRequest->m_id); 320 | } 321 | } else 322 | { 323 | printf("DnsResolver::handleRequest() id=%I64u select error=%d\n", pRequest->m_id, GetLastError()); 324 | } 325 | } else 326 | { 327 | printf("DnsResolver::handleRequest() id=%I64u sendto error=%d\n", pRequest->m_id, GetLastError()); 328 | } 329 | 330 | } 331 | 332 | void threadProc() 333 | { 334 | HANDLE handles[] = { m_jobAvailableEvent, m_stopEvent }; 335 | DNS_REQUEST * pRequest; 336 | 337 | SOCKET s; 338 | 339 | s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 340 | if (s == INVALID_SOCKET) 341 | return; 342 | 343 | for (;;) 344 | { 345 | DWORD res = WaitForMultipleObjects(2, handles, FALSE, INFINITE); 346 | 347 | if (res == (WAIT_OBJECT_0+1)) 348 | break; 349 | 350 | for (;;) 351 | { 352 | { 353 | AutoLock lock(m_cs); 354 | if (m_dnsRequestQueue.empty()) 355 | { 356 | break; 357 | } 358 | 359 | pRequest = m_dnsRequestQueue.front(); 360 | m_dnsRequestQueue.pop(); 361 | } 362 | 363 | handleRequest(pRequest, s); 364 | 365 | delete pRequest; 366 | } 367 | } 368 | 369 | closesocket(s); 370 | } 371 | 372 | static unsigned WINAPI _threadProc(void* pData) 373 | { 374 | (reinterpret_cast(pData))->threadProc(); 375 | return 0; 376 | } 377 | 378 | private: 379 | typedef std::vector tThreads; 380 | tThreads m_threads; 381 | 382 | typedef std::queue tDnsRequestQueue; 383 | tDnsRequestQueue m_dnsRequestQueue; 384 | 385 | AutoEventHandle m_jobAvailableEvent; 386 | AutoHandle m_stopEvent; 387 | 388 | AutoCriticalSection m_cs; 389 | }; 390 | 391 | DnsResolver g_dnsResolver; 392 | 393 | IPEventHandler ipEventHandler; 394 | 395 | // Forward declarations 396 | void printAddrInfo(bool created, ENDPOINT_ID id, PNF_UDP_CONN_INFO pConnInfo); 397 | void printConnInfo(bool connected, ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo); 398 | 399 | struct UDP_CONTEXT 400 | { 401 | UDP_CONTEXT(PNF_UDP_OPTIONS options) 402 | { 403 | if (options) 404 | { 405 | m_options = (PNF_UDP_OPTIONS)new char[sizeof(NF_UDP_OPTIONS) + options->optionsLength]; 406 | memcpy(m_options, options, sizeof(NF_UDP_OPTIONS) + options->optionsLength - 1); 407 | } else 408 | { 409 | m_options = NULL; 410 | } 411 | } 412 | 413 | ~UDP_CONTEXT() 414 | { 415 | if (m_options) 416 | delete[] m_options; 417 | } 418 | 419 | PNF_UDP_OPTIONS m_options; 420 | }; 421 | 422 | 423 | 424 | // 425 | // API events handler 426 | // 427 | class EventHandler : public NF_EventHandler, public UdpProxy::UDPProxyHandler 428 | { 429 | TcpProxy::LocalTCPProxy m_tcpProxy; 430 | 431 | typedef std::map tUdpCtxMap; 432 | tUdpCtxMap m_udpCtxMap; 433 | 434 | UdpProxy::UDPProxy m_udpProxy; 435 | 436 | typedef std::set tIdSet; 437 | tIdSet m_filteredUdpIds; 438 | 439 | AutoCriticalSection m_cs; 440 | 441 | 442 | public: 443 | 444 | bool init() 445 | { 446 | bool result = false; 447 | 448 | for (;;) 449 | { 450 | if (!m_udpProxy.init(this, 451 | (char*)g_proxyAddress, 452 | (((sockaddr*)g_proxyAddress)->sa_family == AF_INET6)? sizeof(sockaddr_in6) : sizeof(sockaddr_in), 453 | g_userName.empty()? NULL : g_userName.c_str(), 454 | g_userPassword.empty()? NULL : g_userPassword.c_str())) 455 | { 456 | printf("Unable to start UDP proxy"); 457 | break; 458 | } 459 | 460 | if (!m_tcpProxy.init(htons(8888))) 461 | { 462 | printf("Unable to start TCP proxy"); 463 | break; 464 | } 465 | 466 | m_tcpProxy.setProxy(0, TcpProxy::PROXY_SOCKS5, 467 | (char*)g_proxyAddress, 468 | (((sockaddr*)g_proxyAddress)->sa_family == AF_INET6)? sizeof(sockaddr_in6) : sizeof(sockaddr_in), 469 | g_userName.empty()? NULL : g_userName.c_str(), 470 | g_userPassword.empty()? NULL : g_userPassword.c_str()); 471 | 472 | result = true; 473 | 474 | break; 475 | } 476 | 477 | if (!result) 478 | { 479 | free(); 480 | } 481 | 482 | return result; 483 | } 484 | 485 | void free() 486 | { 487 | m_udpProxy.free(); 488 | m_tcpProxy.free(); 489 | 490 | AutoLock lock(m_cs); 491 | while (!m_udpCtxMap.empty()) 492 | { 493 | tUdpCtxMap::iterator it = m_udpCtxMap.begin(); 494 | delete it->second; 495 | m_udpCtxMap.erase(it); 496 | } 497 | m_filteredUdpIds.clear(); 498 | } 499 | 500 | virtual void onUdpReceiveComplete(unsigned __int64 id, char * buf, int len, char * remoteAddress, int remoteAddressLen) 501 | { 502 | AutoLock lock(m_cs); 503 | 504 | tUdpCtxMap::iterator it = m_udpCtxMap.find(id); 505 | if (it == m_udpCtxMap.end()) 506 | return; 507 | 508 | char remoteAddr[MAX_PATH]; 509 | DWORD dwLen; 510 | 511 | dwLen = sizeof(remoteAddr); 512 | WSAAddressToString((sockaddr*)remoteAddress, 513 | (((sockaddr*)remoteAddress)->sa_family == AF_INET6)? sizeof(sockaddr_in6) : sizeof(sockaddr_in), 514 | NULL, 515 | remoteAddr, 516 | &dwLen); 517 | 518 | printf("onUdpReceiveComplete id=%I64u len=%d remoteAddress=%s\n", id, len, remoteAddr); 519 | // fflush(stdout); 520 | 521 | nf_udpPostReceive(id, (const unsigned char*)remoteAddress, buf, len, it->second->m_options); 522 | } 523 | 524 | virtual void threadStart() 525 | { 526 | } 527 | 528 | virtual void threadEnd() 529 | { 530 | } 531 | 532 | // 533 | // TCP events 534 | // 535 | virtual void tcpConnectRequest(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo) 536 | { 537 | printf("tcpConnectRequest id=%I64u\n", id); 538 | 539 | sockaddr * pAddr = (sockaddr*)pConnInfo->remoteAddress; 540 | int addrLen = (pAddr->sa_family == AF_INET6)? sizeof(sockaddr_in6) : sizeof(sockaddr_in); 541 | 542 | // Don't redirect the connection if it is already redirected 543 | if (memcmp(pAddr, g_proxyAddress, addrLen) == 0) 544 | { 545 | printf("tcpConnectRequest id=%I64u bypass already redirected\n", id); 546 | return; 547 | } 548 | 549 | if (g_processNamesAllow.size() > 0) 550 | { 551 | if (checkProcessNameInAllow(pConnInfo->processId)) 552 | { 553 | printf("tcpConnectRequest id=%I64u bypass process\n", id); 554 | return; 555 | } 556 | } 557 | 558 | if (g_processNamesFilter.size() > 0) 559 | { 560 | if (!checkProcessNameInFilter(pConnInfo->processId)) 561 | { 562 | printf("tcpConnectRequest id=%I64u bypass process\n", id); 563 | return; 564 | } 565 | } 566 | 567 | if (!m_tcpProxy.isIPFamilyAvailable(pAddr->sa_family)) 568 | { 569 | printf("tcpConnectRequest id=%I64u bypass ipFamily %d\n", id, pAddr->sa_family); 570 | return; 571 | } 572 | 573 | m_tcpProxy.setConnInfo(pConnInfo); 574 | 575 | // Redirect the connection 576 | if (pAddr->sa_family == AF_INET) 577 | { 578 | sockaddr_in addr; 579 | memset(&addr, 0, sizeof(addr)); 580 | addr.sin_family = AF_INET; 581 | 582 | if (((sockaddr_in*)pConnInfo->localAddress)->sin_addr.S_un.S_addr != 0) 583 | { 584 | addr.sin_addr.S_un.S_addr = ((sockaddr_in*)pConnInfo->localAddress)->sin_addr.S_un.S_addr; 585 | } else 586 | { 587 | addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); 588 | } 589 | 590 | addr.sin_port = m_tcpProxy.getPort(); 591 | 592 | memcpy(pConnInfo->remoteAddress, &addr, sizeof(addr)); 593 | } else 594 | { 595 | sockaddr_in6 addr; 596 | memset(&addr, 0, sizeof(addr)); 597 | addr.sin6_family = AF_INET6; 598 | 599 | char zero[16] = {0}; 600 | if (memcmp(&((sockaddr_in6*)pConnInfo->localAddress)->sin6_addr, zero, 16) != 0) 601 | { 602 | memcpy(&addr.sin6_addr, &((sockaddr_in6*)pConnInfo->localAddress)->sin6_addr, 16); 603 | } else 604 | { 605 | addr.sin6_addr.u.Byte[15] = 1; 606 | } 607 | 608 | addr.sin6_port = m_tcpProxy.getPort(); 609 | 610 | memcpy(pConnInfo->remoteAddress, &addr, sizeof(addr)); 611 | } 612 | 613 | // Specify current process id to avoid blocking connection redirected to local proxy 614 | pConnInfo->processId = GetCurrentProcessId(); 615 | } 616 | 617 | virtual void tcpConnected(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo) 618 | { 619 | printConnInfo(true, id, pConnInfo); 620 | fflush(stdout); 621 | } 622 | 623 | virtual void tcpClosed(ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo) 624 | { 625 | printConnInfo(false, id, pConnInfo); 626 | fflush(stdout); 627 | } 628 | 629 | virtual void tcpReceive(ENDPOINT_ID id, const char * buf, int len) 630 | { 631 | printf("tcpReceive id=%I64u len=%d\n", id, len); 632 | // Send the packet to application 633 | nf_tcpPostReceive(id, buf, len); 634 | } 635 | 636 | virtual void tcpSend(ENDPOINT_ID id, const char * buf, int len) 637 | { 638 | printf("tcpSend id=%I64u len=%d\n", id, len); 639 | // Send the packet to server 640 | nf_tcpPostSend(id, buf, len); 641 | } 642 | 643 | virtual void tcpCanReceive(ENDPOINT_ID id) 644 | { 645 | } 646 | 647 | virtual void tcpCanSend(ENDPOINT_ID id) 648 | { 649 | } 650 | 651 | // 652 | // UDP events 653 | // 654 | 655 | virtual void udpCreated(ENDPOINT_ID id, PNF_UDP_CONN_INFO pConnInfo) 656 | { 657 | printAddrInfo(true, id, pConnInfo); 658 | fflush(stdout); 659 | 660 | if (g_processNamesAllow.size() > 0) 661 | { 662 | if (checkProcessNameInAllow(pConnInfo->processId)) 663 | { 664 | printf("udpCreated id=%I64u bypass process\n", id); 665 | return; 666 | } 667 | } 668 | if (g_processNamesFilter.size() > 0) 669 | { 670 | if (!checkProcessNameInFilter(pConnInfo->processId)) 671 | { 672 | printf("udpCreated id=%I64u bypass process\n", id); 673 | return; 674 | } 675 | } 676 | AutoLock lock(m_cs); 677 | m_filteredUdpIds.insert(id); 678 | } 679 | 680 | virtual void udpConnectRequest(ENDPOINT_ID id, PNF_UDP_CONN_REQUEST pConnReq) 681 | { 682 | printf("udpConnectRequest id=%I64u\n", id); 683 | fflush(stdout); 684 | } 685 | 686 | virtual void udpClosed(ENDPOINT_ID id, PNF_UDP_CONN_INFO pConnInfo) 687 | { 688 | printAddrInfo(false, id, pConnInfo); 689 | fflush(stdout); 690 | 691 | m_udpProxy.deleteProxyConnection(id); 692 | 693 | AutoLock lock(m_cs); 694 | 695 | tUdpCtxMap::iterator it = m_udpCtxMap.find(id); 696 | if (it != m_udpCtxMap.end()) 697 | { 698 | delete it->second; 699 | m_udpCtxMap.erase(it); 700 | } 701 | 702 | m_filteredUdpIds.erase(id); 703 | } 704 | 705 | virtual void udpReceive(ENDPOINT_ID id, const unsigned char * remoteAddress, const char * buf, int len, PNF_UDP_OPTIONS options) 706 | { 707 | char remoteAddr[MAX_PATH]; 708 | DWORD dwLen; 709 | 710 | dwLen = sizeof(remoteAddr); 711 | WSAAddressToString((sockaddr*)remoteAddress, 712 | (((sockaddr*)remoteAddress)->sa_family == AF_INET6)? sizeof(sockaddr_in6) : sizeof(sockaddr_in), 713 | NULL, 714 | remoteAddr, 715 | &dwLen); 716 | 717 | printf("udpReceive id=%I64u len=%d remoteAddress=%s\n", id, len, remoteAddr); 718 | // fflush(stdout); 719 | 720 | // Send the packet to application 721 | nf_udpPostReceive(id, remoteAddress, buf, len, options); 722 | } 723 | 724 | virtual void udpSend(ENDPOINT_ID id, const unsigned char * remoteAddress, const char * buf, int len, PNF_UDP_OPTIONS options) 725 | { 726 | char remoteAddr[MAX_PATH]; 727 | DWORD dwLen; 728 | 729 | dwLen = sizeof(remoteAddr); 730 | WSAAddressToString((sockaddr*)remoteAddress, 731 | (((sockaddr*)remoteAddress)->sa_family == AF_INET6)? sizeof(sockaddr_in6) : sizeof(sockaddr_in), 732 | NULL, 733 | remoteAddr, 734 | &dwLen); 735 | 736 | printf("udpSend id=%I64u len=%d remoteAddress=%s\n", id, len, remoteAddr); 737 | // fflush(stdout); 738 | 739 | if (redirectDns) 740 | { 741 | if ((((sockaddr*)remoteAddress)->sa_family == AF_INET6) ? ((sockaddr_in6*)remoteAddress)->sin6_port == htons(53) : ((sockaddr_in*)remoteAddress)->sin_port == htons(53)) 742 | { 743 | g_dnsResolver.addRequest(new DNS_REQUEST(id, remoteAddress, buf, len, options)); 744 | return; 745 | } 746 | } 747 | 748 | { 749 | AutoLock lock(m_cs); 750 | 751 | tIdSet::iterator itid = m_filteredUdpIds.find(id); 752 | if (itid == m_filteredUdpIds.end()) 753 | { 754 | nf_udpPostSend(id, remoteAddress, buf, len, options); 755 | return; 756 | } 757 | 758 | tUdpCtxMap::iterator it = m_udpCtxMap.find(id); 759 | if (it == m_udpCtxMap.end()) 760 | { 761 | if (!m_udpProxy.createProxyConnection(id)) 762 | return; 763 | 764 | m_udpCtxMap[id] = new UDP_CONTEXT(options); 765 | } 766 | } 767 | 768 | { 769 | int addrLen = (((sockaddr*)remoteAddress)->sa_family == AF_INET)? sizeof(sockaddr_in) : sizeof(sockaddr_in6); 770 | if (!m_udpProxy.udpSend(id, (char*)buf, len, (char*)remoteAddress, addrLen)) 771 | { 772 | nf_udpPostSend(id, remoteAddress, buf, len, options); 773 | } 774 | } 775 | } 776 | 777 | virtual void udpCanReceive(ENDPOINT_ID id) 778 | { 779 | } 780 | 781 | virtual void udpCanSend(ENDPOINT_ID id) 782 | { 783 | } 784 | }; 785 | 786 | void usage() 787 | { 788 | printf("Usage: SocksRedirector.exe -r IP:port [-g \"\"] [-p \"\"] [-user ] [-password ] [-dns IP:port]\n" \ 789 | "IP:port : tunnel TCP/UDP traffic via SOCKS proxy using specified IP:port\n" \ 790 | "-g : (global mode, prior to process mode) redirect the traffic except for those of the specified processes (it is possible to specify multiple names divided by ',')\n" \ 791 | "-p : (process mode) redirect the traffic of the specified processes (it is possible to specify multiple names divided by ',')\n" \ 792 | "-dns : hijack DNS requests and redirect to specified specified IP:port\n" \ 793 | "-icmp : reply ICMP locally after specified millisecond(s)\n" \ 794 | ); 795 | exit(0); 796 | } 797 | 798 | bool stringToIPv6(char * str, char * ipBytes) 799 | { 800 | int err, addrLen; 801 | sockaddr_in6 addr; 802 | 803 | addrLen = sizeof(addr); 804 | err = WSAStringToAddress(str, AF_INET6, NULL, (LPSOCKADDR)&addr, &addrLen); 805 | if (err < 0) 806 | { 807 | return false; 808 | } 809 | 810 | memcpy(ipBytes, &addr.sin6_addr, NF_MAX_IP_ADDRESS_LENGTH); 811 | 812 | return true; 813 | } 814 | 815 | int main(int argc, char* argv[]) 816 | { 817 | EventHandler eh; 818 | NF_RULE rule; 819 | NF_RULE_EX ruleEx; 820 | WSADATA wsaData; 821 | 822 | // This call is required for WSAAddressToString 823 | ::WSAStartup(MAKEWORD(2, 2), &wsaData); 824 | 825 | #ifdef _DEBUG 826 | _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); 827 | _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG); 828 | #endif 829 | 830 | #if defined(_DEBUG) || defined(_RELEASE_LOG) 831 | DBGLogger::instance().init("SocksRedirectorLog.txt"); 832 | #endif 833 | 834 | memset(&g_proxyAddress, 0, sizeof(g_proxyAddress)); 835 | 836 | if (argc < 2) 837 | usage(); 838 | 839 | for (int i=1; i < argc; i += 2) 840 | { 841 | if (stricmp(argv[i], "-r") == 0) 842 | { 843 | int err, addrLen; 844 | 845 | addrLen = sizeof(g_proxyAddress); 846 | err = WSAStringToAddress(argv[i+1], AF_INET, NULL, (LPSOCKADDR)&g_proxyAddress, &addrLen); 847 | if (err < 0) 848 | { 849 | addrLen = sizeof(g_proxyAddress); 850 | err = WSAStringToAddress(argv[i+1], AF_INET6, NULL, (LPSOCKADDR)&g_proxyAddress, &addrLen); 851 | if (err < 0) 852 | { 853 | printf("WSAStringToAddress failed, err=%d", WSAGetLastError()); 854 | usage(); 855 | } 856 | } 857 | 858 | printf("Redirect to: %s\n", argv[i+1]); 859 | } else 860 | if (stricmp(argv[i], "-g") == 0) 861 | { 862 | parseValue(argv[i+1], g_processNamesAllow); 863 | printf("(Global mode) bypass process name(s): %s\n", argv[i+1]); 864 | } else 865 | if (stricmp(argv[i], "-p") == 0) 866 | { 867 | parseValue(argv[i+1], g_processNamesFilter); 868 | printf("(Process mode) proxy process name(s): %s\n", argv[i+1]); 869 | } else 870 | if (stricmp(argv[i], "-user") == 0) 871 | { 872 | g_userName = argv[i+1]; 873 | 874 | printf("User name: %s\n", argv[i+1]); 875 | } else 876 | if (stricmp(argv[i], "-password") == 0) 877 | { 878 | g_userPassword = argv[i+1]; 879 | 880 | printf("User password: %s\n", argv[i+1]); 881 | } else 882 | if (stricmp(argv[i], "-dns") == 0) 883 | { 884 | redirectDns = true; 885 | int err, addrLen; 886 | 887 | addrLen = sizeof(g_dnsAddress); 888 | err = WSAStringToAddress(argv[i+1], AF_INET, NULL, (LPSOCKADDR)&g_dnsAddress, &addrLen); 889 | if (err < 0) 890 | { 891 | addrLen = sizeof(g_dnsAddress); 892 | err = WSAStringToAddress(argv[i+1], AF_INET6, NULL, (LPSOCKADDR)&g_dnsAddress, &addrLen); 893 | if (err < 0) 894 | { 895 | printf("WSAStringToAddress failed, err=%d", WSAGetLastError()); 896 | usage(); 897 | } 898 | } 899 | 900 | printf("Redirect DNS to: %s\n", argv[i+1]); 901 | } else 902 | if (stricmp(argv[i], "-icmp") == 0) 903 | { 904 | replyIcmp = true; 905 | delay = atoi(argv[i + 1]); 906 | if (delay < 0) 907 | { 908 | printf("Invalid ICMP delay millisecond: %s\n", argv[i+1]); 909 | usage(); 910 | } 911 | } 912 | else 913 | { 914 | usage(); 915 | } 916 | } 917 | 918 | printf("Press enter to stop...\n\n"); 919 | 920 | g_dnsResolver.init(10); 921 | 922 | if (!eh.init()) 923 | { 924 | printf("Failed to initialize the event handler"); 925 | return -1; 926 | } 927 | 928 | // Initialize the library and start filtering thread 929 | if (nf_init(NFDRIVER_NAME, &eh) != NF_STATUS_SUCCESS) 930 | { 931 | printf("Failed to connect to driver"); 932 | return -1; 933 | } 934 | 935 | // Bypass local traffic 936 | memset(&rule, 0, sizeof(rule)); 937 | rule.filteringFlag = NF_ALLOW; 938 | rule.ip_family = AF_INET; 939 | *((unsigned long*)rule.remoteIpAddress) = inet_addr("127.0.0.1"); 940 | *((unsigned long*)rule.remoteIpAddressMask) = inet_addr("255.0.0.0"); 941 | nf_addRule(&rule, FALSE); 942 | 943 | memset(&rule, 0, sizeof(rule)); 944 | rule.filteringFlag = NF_ALLOW; 945 | rule.ip_family = AF_INET6; 946 | stringToIPv6("::1", (char*)rule.remoteIpAddress); 947 | nf_addRule(&rule, FALSE); 948 | 949 | memset(&rule, 0, sizeof(rule)); 950 | rule.filteringFlag = NF_ALLOW; 951 | rule.ip_family = AF_INET6; 952 | stringToIPv6("0:0:0:0:0:ffff:7f00:001", (char*)rule.remoteIpAddress); 953 | nf_addRule(&rule, FALSE); 954 | 955 | // reply icmp locally 956 | if (replyIcmp) 957 | { 958 | nf_setIPEventHandler(&ipEventHandler); 959 | memset(&rule, 0, sizeof(rule)); 960 | rule.protocol = IPPROTO_ICMP; 961 | rule.direction = NF_D_OUT; 962 | rule.filteringFlag = NF_FILTER_AS_IP_PACKETS; 963 | nf_addRule(&rule, FALSE); 964 | 965 | memset(&rule, 0, sizeof(NF_RULE)); 966 | rule.protocol = IPPROTO_ICMPV6; 967 | rule.direction = NF_D_OUT; 968 | rule.filteringFlag = NF_FILTER_AS_IP_PACKETS; 969 | nf_addRule(&rule, FALSE); 970 | } 971 | 972 | // Bypass processes 973 | for (size_t i = 0; i < g_processNamesAllow.size(); i++) 974 | { 975 | memset(&ruleEx, 0, sizeof(ruleEx)); 976 | ruleEx.filteringFlag = NF_ALLOW; 977 | const wchar_t *p = std::wstring(g_processNamesAllow[i].begin(), g_processNamesAllow[i].end()).c_str(); 978 | wcsncpy((wchar_t*)ruleEx.processName, p, MAX_PATH); 979 | nf_addRuleEx(&ruleEx, FALSE); 980 | } 981 | 982 | // Filter processes 983 | for (size_t i = 0; i < g_processNamesFilter.size(); i++) 984 | { 985 | memset(&ruleEx, 0, sizeof(ruleEx)); 986 | ruleEx.filteringFlag = NF_FILTER; 987 | const wchar_t *p = std::wstring(g_processNamesFilter[i].begin(), g_processNamesFilter[i].end()).c_str(); 988 | wcsncpy((wchar_t*)ruleEx.processName, p, MAX_PATH); 989 | nf_addRuleEx(&ruleEx, FALSE); 990 | } 991 | 992 | // Filter UDP packets 993 | memset(&rule, 0, sizeof(rule)); 994 | rule.protocol = IPPROTO_UDP; 995 | rule.filteringFlag = NF_FILTER; 996 | nf_addRule(&rule, FALSE); 997 | 998 | // Filter TCP connect requests 999 | memset(&rule, 0, sizeof(rule)); 1000 | rule.protocol = IPPROTO_TCP; 1001 | rule.direction = NF_D_OUT; 1002 | rule.filteringFlag = NF_INDICATE_CONNECT_REQUESTS; 1003 | nf_addRule(&rule, FALSE); 1004 | 1005 | // Wait for enter 1006 | getchar(); 1007 | 1008 | // Free the library 1009 | nf_free(); 1010 | 1011 | g_dnsResolver.free(); 1012 | 1013 | eh.free(); 1014 | 1015 | ::WSACleanup(); 1016 | 1017 | return 0; 1018 | } 1019 | 1020 | 1021 | /** 1022 | * Print the address information 1023 | **/ 1024 | void printAddrInfo(bool created, ENDPOINT_ID id, PNF_UDP_CONN_INFO pConnInfo) 1025 | { 1026 | char localAddr[MAX_PATH] = ""; 1027 | sockaddr * pAddr; 1028 | DWORD dwLen; 1029 | char processName[MAX_PATH] = ""; 1030 | 1031 | pAddr = (sockaddr*)pConnInfo->localAddress; 1032 | dwLen = sizeof(localAddr); 1033 | 1034 | WSAAddressToString((LPSOCKADDR)pAddr, 1035 | (pAddr->sa_family == AF_INET6)? sizeof(sockaddr_in6) : sizeof(sockaddr_in), 1036 | NULL, 1037 | localAddr, 1038 | &dwLen); 1039 | 1040 | if (created) 1041 | { 1042 | if (!nf_getProcessName(pConnInfo->processId, processName, sizeof(processName)/sizeof(processName[0]))) 1043 | { 1044 | processName[0] = '\0'; 1045 | } 1046 | 1047 | printf("udpCreated id=%I64u pid=%d local=%s\n\tProcess: %s\n", 1048 | id, 1049 | pConnInfo->processId, 1050 | localAddr, 1051 | processName); 1052 | } else 1053 | { 1054 | printf("udpClosed id=%I64u pid=%d local=%s\n", 1055 | id, 1056 | pConnInfo->processId, 1057 | localAddr); 1058 | } 1059 | 1060 | } 1061 | 1062 | /** 1063 | * Print the connection information 1064 | **/ 1065 | void printConnInfo(bool connected, ENDPOINT_ID id, PNF_TCP_CONN_INFO pConnInfo) 1066 | { 1067 | char localAddr[MAX_PATH] = ""; 1068 | char remoteAddr[MAX_PATH] = ""; 1069 | DWORD dwLen; 1070 | sockaddr * pAddr; 1071 | char processName[MAX_PATH] = ""; 1072 | 1073 | pAddr = (sockaddr*)pConnInfo->localAddress; 1074 | dwLen = sizeof(localAddr); 1075 | 1076 | WSAAddressToString((LPSOCKADDR)pAddr, 1077 | (pAddr->sa_family == AF_INET6)? sizeof(sockaddr_in6) : sizeof(sockaddr_in), 1078 | NULL, 1079 | localAddr, 1080 | &dwLen); 1081 | 1082 | pAddr = (sockaddr*)pConnInfo->remoteAddress; 1083 | dwLen = sizeof(remoteAddr); 1084 | 1085 | WSAAddressToString((LPSOCKADDR)pAddr, 1086 | (pAddr->sa_family == AF_INET6)? sizeof(sockaddr_in6) : sizeof(sockaddr_in), 1087 | NULL, 1088 | remoteAddr, 1089 | &dwLen); 1090 | 1091 | if (connected) 1092 | { 1093 | if (!nf_getProcessName(pConnInfo->processId, processName, sizeof(processName)/sizeof(processName[0]))) 1094 | { 1095 | processName[0] = '\0'; 1096 | } 1097 | 1098 | printf("tcpConnected id=%I64u flag=%d pid=%d direction=%s local=%s remote=%s (conn.table size %d)\n\tProcess: %s\n", 1099 | id, 1100 | pConnInfo->filteringFlag, 1101 | pConnInfo->processId, 1102 | (pConnInfo->direction == NF_D_IN)? "in" : ((pConnInfo->direction == NF_D_OUT)? "out" : "none"), 1103 | localAddr, 1104 | remoteAddr, 1105 | nf_getConnCount(), 1106 | processName); 1107 | } else 1108 | { 1109 | printf("tcpClosed id=%I64u flag=%d pid=%d direction=%s local=%s remote=%s (conn.table size %d)\n", 1110 | id, 1111 | pConnInfo->filteringFlag, 1112 | pConnInfo->processId, 1113 | (pConnInfo->direction == NF_D_IN)? "in" : ((pConnInfo->direction == NF_D_OUT)? "out" : "none"), 1114 | localAddr, 1115 | remoteAddr, 1116 | nf_getConnCount()); 1117 | } 1118 | 1119 | } 1120 | 1121 | -------------------------------------------------------------------------------- /src/SocksRedirector.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Debug 10 | x64 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 17.0 23 | {A7D5846D-595B-4A41-9AAE-6A87C2BD6D83} 24 | Win32Proj 25 | 26 | 27 | 28 | Application 29 | v143 30 | MultiByte 31 | true 32 | 33 | 34 | Application 35 | v143 36 | MultiByte 37 | 38 | 39 | Application 40 | v143 41 | MultiByte 42 | true 43 | 44 | 45 | Application 46 | v143 47 | MultiByte 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | <_ProjectFileVersion>17.0.32819.101 67 | 68 | 69 | $(Configuration)\$(Platform)\ 70 | $(Configuration)\$(Platform)\ 71 | true 72 | 73 | 74 | $(Configuration)\$(Platform)\ 75 | $(Configuration)\$(Platform)\ 76 | true 77 | 78 | 79 | $(Configuration)\$(Platform)\ 80 | $(Configuration)\$(Platform)\ 81 | false 82 | 83 | 84 | $(Configuration)\$(Platform)\ 85 | $(Configuration)\$(Platform)\ 86 | false 87 | 88 | 89 | 90 | Disabled 91 | ..\include;%(AdditionalIncludeDirectories) 92 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 93 | true 94 | EnableFastChecks 95 | MultiThreadedDebugDLL 96 | Use 97 | Level3 98 | EditAndContinue 99 | 100 | 101 | nfapi.lib;ws2_32.lib;%(AdditionalDependencies) 102 | ..\bin\$(Configuration)\$(Platform)\$(ProjectName).exe 103 | ..\lib\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) 104 | true 105 | Console 106 | MachineX86 107 | 108 | 109 | 110 | 111 | X64 112 | 113 | 114 | Disabled 115 | ..\include;%(AdditionalIncludeDirectories) 116 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 117 | true 118 | EnableFastChecks 119 | MultiThreadedDebugDLL 120 | Use 121 | Level3 122 | ProgramDatabase 123 | 124 | 125 | nfapi.lib;ws2_32.lib;%(AdditionalDependencies) 126 | ..\bin\$(Configuration)\$(Platform)\$(ProjectName).exe 127 | ..\lib\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) 128 | true 129 | Console 130 | MachineX64 131 | 132 | 133 | 134 | 135 | ..\include;%(AdditionalIncludeDirectories) 136 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 137 | MultiThreaded 138 | Use 139 | Level3 140 | ProgramDatabase 141 | 142 | 143 | nfapi.lib;ws2_32.lib;%(AdditionalDependencies) 144 | ..\bin\$(Configuration)\$(Platform)\$(ProjectName).exe 145 | ..\lib\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) 146 | true 147 | Console 148 | true 149 | true 150 | MachineX86 151 | 152 | 153 | 154 | 155 | X64 156 | 157 | 158 | ..\include;%(AdditionalIncludeDirectories) 159 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 160 | MultiThreaded 161 | Use 162 | Level3 163 | ProgramDatabase 164 | 165 | 166 | nfapi.lib;ws2_32.lib;%(AdditionalDependencies) 167 | ..\bin\$(Configuration)\$(Platform)\$(ProjectName).exe 168 | ..\lib\$(Configuration)\$(Platform);%(AdditionalLibraryDirectories) 169 | true 170 | Console 171 | true 172 | true 173 | MachineX64 174 | 175 | 176 | 177 | 178 | 179 | Create 180 | Create 181 | Create 182 | Create 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | -------------------------------------------------------------------------------- /src/UdpProxy.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "sync.h" 9 | #include "socksdefs.h" 10 | #include "iocp.h" 11 | 12 | namespace UdpProxy 13 | { 14 | 15 | #define PACKET_SIZE 65536 16 | 17 | typedef std::vector tBuffer; 18 | 19 | enum OV_TYPE 20 | { 21 | OVT_CONNECT, 22 | OVT_TCP_SEND, 23 | OVT_TCP_RECEIVE, 24 | OVT_UDP_SEND, 25 | OVT_UDP_RECEIVE 26 | }; 27 | 28 | struct OV_DATA 29 | { 30 | OV_DATA() 31 | { 32 | memset(&ol, 0, sizeof(ol)); 33 | } 34 | 35 | OVERLAPPED ol; 36 | unsigned __int64 id; 37 | OV_TYPE type; 38 | char remoteAddress[NF_MAX_ADDRESS_LENGTH]; 39 | int remoteAddressLen; 40 | tBuffer buffer; 41 | }; 42 | 43 | typedef std::set tOvDataSet; 44 | 45 | enum PROXY_STATE 46 | { 47 | PS_NONE, 48 | PS_AUTH, 49 | PS_AUTH_NEGOTIATION, 50 | PS_UDP_ASSOC, 51 | PS_CONNECTED, 52 | PS_CLOSED 53 | }; 54 | 55 | struct UDP_PACKET 56 | { 57 | char remoteAddress[NF_MAX_ADDRESS_LENGTH]; 58 | int remoteAddressLen; 59 | tBuffer buffer; 60 | }; 61 | 62 | typedef std::list tPacketList; 63 | 64 | struct PROXY_DATA 65 | { 66 | PROXY_DATA() 67 | { 68 | tcpSocket = INVALID_SOCKET; 69 | udpSocket = INVALID_SOCKET; 70 | proxyState = PS_NONE; 71 | memset(remoteAddress, 0, sizeof(remoteAddress)); 72 | remoteAddressLen = 0; 73 | udpRecvStarted = false; 74 | ipFamily = AF_INET; 75 | } 76 | ~PROXY_DATA() 77 | { 78 | if (tcpSocket != INVALID_SOCKET) 79 | { 80 | shutdown(tcpSocket, SD_BOTH); 81 | closesocket(tcpSocket); 82 | } 83 | if (udpSocket != INVALID_SOCKET) 84 | { 85 | closesocket(udpSocket); 86 | } 87 | while (!udpSendPackets.empty()) 88 | { 89 | tPacketList::iterator it = udpSendPackets.begin(); 90 | delete (*it); 91 | udpSendPackets.erase(it); 92 | } 93 | } 94 | 95 | SOCKET tcpSocket; 96 | SOCKET udpSocket; 97 | 98 | PROXY_STATE proxyState; 99 | 100 | char remoteAddress[NF_MAX_ADDRESS_LENGTH]; 101 | int remoteAddressLen; 102 | 103 | std::string userName; 104 | std::string userPassword; 105 | 106 | tPacketList udpSendPackets; 107 | 108 | bool udpRecvStarted; 109 | 110 | u_short ipFamily; 111 | }; 112 | 113 | typedef std::map tSocketMap; 114 | 115 | class UDPProxyHandler 116 | { 117 | public: 118 | virtual void onUdpReceiveComplete(unsigned __int64 id, char * buf, int len, char * remoteAddress, int remoteAddressLen) = 0; 119 | }; 120 | 121 | 122 | class UDPProxy : public IOCPHandler 123 | { 124 | public: 125 | UDPProxy() : m_pProxyHandler(NULL) 126 | { 127 | } 128 | 129 | ~UDPProxy() 130 | { 131 | } 132 | 133 | void * getExtensionFunction(SOCKET s, const GUID *which_fn) 134 | { 135 | void *ptr = NULL; 136 | DWORD bytes=0; 137 | WSAIoctl(s, 138 | SIO_GET_EXTENSION_FUNCTION_POINTER, 139 | (GUID*)which_fn, sizeof(*which_fn), 140 | &ptr, sizeof(ptr), 141 | &bytes, 142 | NULL, 143 | NULL); 144 | return ptr; 145 | } 146 | 147 | bool initExtensions() 148 | { 149 | const GUID connectex = WSAID_CONNECTEX; 150 | 151 | SOCKET s = socket(AF_INET, SOCK_STREAM, 0); 152 | if (s == INVALID_SOCKET) 153 | return false; 154 | 155 | m_pConnectEx = (LPFN_CONNECTEX)getExtensionFunction(s, &connectex); 156 | 157 | closesocket(s); 158 | 159 | return m_pConnectEx != NULL; 160 | } 161 | 162 | bool init(UDPProxyHandler * pProxyHandler, 163 | char * proxyAddress, int proxyAddressLen, 164 | const char * userName = NULL, const char * userPassword = NULL) 165 | { 166 | if (!initExtensions()) 167 | return false; 168 | 169 | if (!m_service.init(this)) 170 | return false; 171 | 172 | m_pProxyHandler = pProxyHandler; 173 | 174 | memcpy(m_proxyAddress, proxyAddress, proxyAddressLen); 175 | m_proxyAddressLen = proxyAddressLen; 176 | 177 | if (userName) 178 | { 179 | m_userName = userName; 180 | } 181 | if (userPassword) 182 | { 183 | m_userPassword = userPassword; 184 | } 185 | 186 | return true; 187 | } 188 | 189 | void free() 190 | { 191 | m_service.free(); 192 | 193 | while (!m_ovDataSet.empty()) 194 | { 195 | tOvDataSet::iterator it = m_ovDataSet.begin(); 196 | delete (*it); 197 | m_ovDataSet.erase(it); 198 | } 199 | while (!m_socketMap.empty()) 200 | { 201 | tSocketMap::iterator it = m_socketMap.begin(); 202 | delete it->second; 203 | m_socketMap.erase(it); 204 | } 205 | } 206 | 207 | bool createProxyConnection(unsigned __int64 id) 208 | { 209 | bool result = false; 210 | 211 | DbgPrint("UDPProxy::createProxyConnection %I64u", id); 212 | 213 | u_short ipFamily = ((sockaddr*)m_proxyAddress)->sa_family; 214 | 215 | for (;;) 216 | { 217 | SOCKET tcpSocket = WSASocket(ipFamily, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); 218 | if (tcpSocket == INVALID_SOCKET) 219 | return false; 220 | 221 | SOCKET udpSocket = WSASocket(ipFamily, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED); 222 | if (udpSocket == INVALID_SOCKET) 223 | { 224 | closesocket(tcpSocket); 225 | return false; 226 | } 227 | 228 | { 229 | AutoLock lock(m_cs); 230 | 231 | PROXY_DATA * pd = new PROXY_DATA(); 232 | pd->tcpSocket = tcpSocket; 233 | pd->udpSocket = udpSocket; 234 | 235 | pd->userName = m_userName; 236 | pd->userPassword = m_userPassword; 237 | 238 | pd->ipFamily = ipFamily; 239 | 240 | m_socketMap[id] = pd; 241 | } 242 | 243 | if (!m_service.registerSocket(tcpSocket)) 244 | break; 245 | 246 | if (!m_service.registerSocket(udpSocket)) 247 | break; 248 | 249 | if (!startConnect(tcpSocket, (sockaddr*)m_proxyAddress, m_proxyAddressLen, id)) 250 | break; 251 | 252 | result = true; 253 | 254 | break; 255 | } 256 | 257 | if (!result) 258 | { 259 | { 260 | AutoLock lock(m_cs); 261 | 262 | tSocketMap::iterator it = m_socketMap.find(id); 263 | if (it != m_socketMap.end()) 264 | { 265 | delete it->second; 266 | m_socketMap.erase(it); 267 | } 268 | } 269 | } 270 | 271 | return result; 272 | } 273 | 274 | void deleteProxyConnection(unsigned __int64 id) 275 | { 276 | DbgPrint("UDPProxy::deleteProxyConnection %I64u", id); 277 | 278 | AutoLock lock(m_cs); 279 | tSocketMap::iterator it = m_socketMap.find(id); 280 | if (it != m_socketMap.end()) 281 | { 282 | delete it->second; 283 | m_socketMap.erase(it); 284 | } 285 | } 286 | 287 | bool udpSend(unsigned __int64 id, char * buf, int len, char * remoteAddress, int remoteAddressLen) 288 | { 289 | SOCKET s; 290 | 291 | // DbgPrint("udpSend %I64u", id); 292 | 293 | { 294 | AutoLock lock(m_cs); 295 | 296 | tSocketMap::iterator it = m_socketMap.find(id); 297 | if (it == m_socketMap.end()) 298 | { 299 | return false; 300 | } 301 | 302 | if (it->second->proxyState != PS_CONNECTED) 303 | { 304 | if (len > 0) 305 | { 306 | UDP_PACKET * p = new UDP_PACKET(); 307 | 308 | memcpy(p->remoteAddress, remoteAddress, remoteAddressLen); 309 | p->remoteAddressLen = remoteAddressLen; 310 | p->buffer.resize(len); 311 | memcpy(&p->buffer[0], buf, len); 312 | 313 | it->second->udpSendPackets.push_back(p); 314 | 315 | // DbgPrint("udpSend %I64u packet pended", id); 316 | } 317 | return true; 318 | } 319 | 320 | s = it->second->udpSocket; 321 | 322 | OV_DATA * pov = newOV_DATA(); 323 | DWORD dwBytes; 324 | 325 | pov->type = OVT_UDP_SEND; 326 | pov->id = id; 327 | 328 | if (len > 0) 329 | { 330 | if (((sockaddr*)remoteAddress)->sa_family == AF_INET) 331 | { 332 | pov->buffer.resize(len + sizeof(SOCKS5_UDP_REQUEST_IPv4)); 333 | 334 | SOCKS5_UDP_REQUEST_IPv4 * pReq = (SOCKS5_UDP_REQUEST_IPv4*)&pov->buffer[0]; 335 | pReq->reserved = 0; 336 | pReq->frag = 0; 337 | pReq->address_type = SOCKS5_ADDR_IPV4; 338 | pReq->address = ((sockaddr_in*)remoteAddress)->sin_addr.S_un.S_addr; 339 | pReq->port = ((sockaddr_in*)remoteAddress)->sin_port; 340 | 341 | memcpy(&pov->buffer[sizeof(SOCKS5_UDP_REQUEST_IPv4)], buf, len); 342 | 343 | } else 344 | { 345 | pov->buffer.resize(len + sizeof(SOCKS5_UDP_REQUEST_IPv6)); 346 | 347 | SOCKS5_UDP_REQUEST_IPv6 * pReq = (SOCKS5_UDP_REQUEST_IPv6*)&pov->buffer[0]; 348 | pReq->reserved = 0; 349 | pReq->frag = 0; 350 | pReq->address_type = SOCKS5_ADDR_IPV6; 351 | memcpy(pReq->address, &((sockaddr_in6*)remoteAddress)->sin6_addr, 16); 352 | pReq->port = ((sockaddr_in6*)remoteAddress)->sin6_port; 353 | 354 | memcpy(&pov->buffer[sizeof(SOCKS5_UDP_REQUEST_IPv6)], buf, len); 355 | } 356 | 357 | } 358 | 359 | WSABUF bufs; 360 | 361 | bufs.buf = &pov->buffer[0]; 362 | bufs.len = (u_long)pov->buffer.size(); 363 | 364 | if (WSASendTo(s, &bufs, 1, &dwBytes, 0, 365 | (sockaddr*)it->second->remoteAddress, it->second->remoteAddressLen, 366 | &pov->ol, NULL) != 0) 367 | { 368 | int err = WSAGetLastError(); 369 | if (err != ERROR_IO_PENDING) 370 | { 371 | pov->type = OVT_UDP_RECEIVE; 372 | pov->buffer.clear(); 373 | if (!m_service.postCompletion(s, 0, &pov->ol)) 374 | { 375 | deleteOV_DATA(pov); 376 | } 377 | return false; 378 | } 379 | } 380 | 381 | if (!it->second->udpRecvStarted) 382 | { 383 | it->second->udpRecvStarted = true; 384 | startUdpReceive(s, id, NULL); 385 | } 386 | } 387 | 388 | return true; 389 | } 390 | 391 | OV_DATA * newOV_DATA() 392 | { 393 | OV_DATA * pov = new OV_DATA(); 394 | AutoLock lock(m_cs); 395 | m_ovDataSet.insert(pov); 396 | return pov; 397 | } 398 | 399 | void deleteOV_DATA(OV_DATA * pov) 400 | { 401 | AutoLock lock(m_cs); 402 | tOvDataSet::iterator it; 403 | it = m_ovDataSet.find(pov); 404 | if (it == m_ovDataSet.end()) 405 | return; 406 | m_ovDataSet.erase(it); 407 | delete pov; 408 | } 409 | 410 | bool startConnect(SOCKET socket, sockaddr * pAddr, int addrLen, unsigned __int64 id) 411 | { 412 | OV_DATA * pov = newOV_DATA(); 413 | pov->type = OVT_CONNECT; 414 | pov->id = id; 415 | 416 | DbgPrint("UDPProxy::startConnect %I64u, socket=%d", id, socket); 417 | 418 | if (pAddr->sa_family == AF_INET) 419 | { 420 | struct sockaddr_in addr; 421 | ZeroMemory(&addr, sizeof(addr)); 422 | addr.sin_family = AF_INET; 423 | 424 | bind(socket, (SOCKADDR*) &addr, sizeof(addr)); 425 | } else 426 | { 427 | struct sockaddr_in6 addr; 428 | ZeroMemory(&addr, sizeof(addr)); 429 | addr.sin6_family = AF_INET6; 430 | 431 | bind(socket, (SOCKADDR*) &addr, sizeof(addr)); 432 | } 433 | 434 | if (!m_pConnectEx(socket, pAddr, addrLen, NULL, 0, NULL, &pov->ol)) 435 | { 436 | int err = WSAGetLastError(); 437 | if (err != ERROR_IO_PENDING) 438 | { 439 | DbgPrint("UDPProxy::startConnect %I64u failed, err=%d", id, err); 440 | deleteOV_DATA(pov); 441 | return false; 442 | } 443 | } 444 | 445 | return true; 446 | } 447 | 448 | 449 | bool startUdpReceive(SOCKET socket, unsigned __int64 id, OV_DATA * pov) 450 | { 451 | DWORD dwBytes, dwFlags; 452 | WSABUF bufs; 453 | 454 | AutoLock lock(m_cs); 455 | 456 | tSocketMap::iterator it = m_socketMap.find(id); 457 | if (it == m_socketMap.end()) 458 | return false; 459 | 460 | if (pov == NULL) 461 | { 462 | pov = newOV_DATA(); 463 | pov->type = OVT_UDP_RECEIVE; 464 | pov->id = id; 465 | pov->buffer.resize(PACKET_SIZE); 466 | } 467 | 468 | bufs.buf = &pov->buffer[0]; 469 | bufs.len = (u_long)pov->buffer.size(); 470 | 471 | dwFlags = 0; 472 | 473 | pov->remoteAddressLen = sizeof(pov->remoteAddress); 474 | 475 | if (WSARecvFrom(socket, &bufs, 1, &dwBytes, &dwFlags, (sockaddr*)pov->remoteAddress, &pov->remoteAddressLen, &pov->ol, NULL) != 0) 476 | { 477 | int err = WSAGetLastError(); 478 | if (err != ERROR_IO_PENDING) 479 | { 480 | if (!m_service.postCompletion(socket, 0, &pov->ol)) 481 | { 482 | deleteOV_DATA(pov); 483 | } 484 | return true; 485 | } 486 | } 487 | 488 | return true; 489 | } 490 | 491 | bool startTcpReceive(SOCKET socket, unsigned __int64 id, OV_DATA * pov) 492 | { 493 | DWORD dwBytes, dwFlags; 494 | WSABUF bufs; 495 | 496 | if (pov == NULL) 497 | { 498 | pov = newOV_DATA(); 499 | pov->type = OVT_TCP_RECEIVE; 500 | pov->id = id; 501 | pov->buffer.resize(PACKET_SIZE); 502 | } 503 | 504 | bufs.buf = &pov->buffer[0]; 505 | bufs.len = (u_long)pov->buffer.size(); 506 | 507 | dwFlags = 0; 508 | 509 | if (WSARecv(socket, &bufs, 1, &dwBytes, &dwFlags, &pov->ol, NULL) != 0) 510 | { 511 | int err = WSAGetLastError(); 512 | if (err != ERROR_IO_PENDING) 513 | { 514 | if (!m_service.postCompletion(socket, 0, &pov->ol)) 515 | { 516 | deleteOV_DATA(pov); 517 | } 518 | return true; 519 | } 520 | } 521 | 522 | return true; 523 | } 524 | 525 | bool startTcpSend(SOCKET socket, char * buf, int len, unsigned __int64 id) 526 | { 527 | OV_DATA * pov = newOV_DATA(); 528 | DWORD dwBytes; 529 | 530 | DbgPrint("UDPProxy::startTcpSend %I64u bytes=%d", id, len); 531 | 532 | pov->id = id; 533 | pov->type = OVT_TCP_SEND; 534 | 535 | if (len > 0) 536 | { 537 | pov->buffer.resize(len); 538 | memcpy(&pov->buffer[0], buf, len); 539 | } 540 | 541 | WSABUF bufs; 542 | 543 | bufs.buf = &pov->buffer[0]; 544 | bufs.len = (u_long)pov->buffer.size(); 545 | 546 | if (WSASend(socket, &bufs, 1, &dwBytes, 0, 547 | &pov->ol, NULL) != 0) 548 | { 549 | int err = WSAGetLastError(); 550 | if (err != ERROR_IO_PENDING) 551 | { 552 | DbgPrint("UDPProxy::startTcpSend %I64u failed, err=%d", id, err); 553 | pov->type = OVT_TCP_RECEIVE; 554 | pov->buffer.clear(); 555 | if (!m_service.postCompletion(socket, 0, &pov->ol)) 556 | { 557 | deleteOV_DATA(pov); 558 | } 559 | return false; 560 | } 561 | } 562 | 563 | return true; 564 | } 565 | 566 | void onUdpSendComplete(SOCKET socket, DWORD dwTransferred, OV_DATA * pov, int error) 567 | { 568 | // DbgPrint("UDPProxy::onUdpSendComplete %I64u bytes=%d, err=%d", pov->id, dwTransferred, error); 569 | deleteOV_DATA(pov); 570 | } 571 | 572 | void onUdpReceiveComplete(SOCKET socket, DWORD dwTransferred, OV_DATA * pov, int error) 573 | { 574 | // DbgPrint("UDPProxy::onUdpReceiveComplete %I64u bytes=%d, err=%d", pov->id, dwTransferred, error); 575 | 576 | if (dwTransferred == 0) 577 | { 578 | deleteOV_DATA(pov); 579 | return; 580 | } 581 | 582 | if (dwTransferred > sizeof(SOCKS5_UDP_REQUEST)) 583 | { 584 | SOCKS5_UDP_REQUEST * pReq = (SOCKS5_UDP_REQUEST*)&pov->buffer[0]; 585 | if (pReq->address_type == SOCKS5_ADDR_IPV4) 586 | { 587 | SOCKS5_UDP_REQUEST_IPv4 * pReqIPv4 = (SOCKS5_UDP_REQUEST_IPv4*)&pov->buffer[0]; 588 | 589 | sockaddr_in addr; 590 | memset(&addr, 0, sizeof(addr)); 591 | addr.sin_family = AF_INET; 592 | addr.sin_addr.S_un.S_addr = pReqIPv4->address; 593 | addr.sin_port = pReqIPv4->port; 594 | 595 | m_pProxyHandler->onUdpReceiveComplete(pov->id, 596 | &pov->buffer[sizeof(SOCKS5_UDP_REQUEST_IPv4)], 597 | dwTransferred - sizeof(SOCKS5_UDP_REQUEST_IPv4), 598 | (char*)&addr, 599 | sizeof(addr)); 600 | } else 601 | if (pReq->address_type == SOCKS5_ADDR_IPV6) 602 | { 603 | SOCKS5_UDP_REQUEST_IPv6 * pReqIPv6 = (SOCKS5_UDP_REQUEST_IPv6*)&pov->buffer[0]; 604 | 605 | sockaddr_in6 addr; 606 | memset(&addr, 0, sizeof(addr)); 607 | addr.sin6_family = AF_INET6; 608 | memcpy(&addr.sin6_addr, pReqIPv6->address, 16); 609 | addr.sin6_port = pReqIPv6->port; 610 | 611 | m_pProxyHandler->onUdpReceiveComplete(pov->id, 612 | &pov->buffer[sizeof(SOCKS5_UDP_REQUEST_IPv6)], 613 | dwTransferred - sizeof(SOCKS5_UDP_REQUEST_IPv6), 614 | (char*)&addr, 615 | sizeof(addr)); 616 | } 617 | } 618 | 619 | memset(&pov->ol, 0, sizeof(pov->ol)); 620 | 621 | startUdpReceive(socket, pov->id, pov); 622 | } 623 | 624 | void setKeepAliveVals(SOCKET s) 625 | { 626 | tcp_keepalive tk; 627 | DWORD dwRet; 628 | 629 | { 630 | AutoLock lock(m_cs); 631 | 632 | tk.onoff = 1; 633 | tk.keepalivetime = 5 * 60 * 1000; 634 | tk.keepaliveinterval = 1000; 635 | } 636 | 637 | int err = WSAIoctl(s, SIO_KEEPALIVE_VALS, 638 | (LPVOID) &tk, 639 | (DWORD) sizeof(tk), 640 | NULL, 641 | 0, 642 | (LPDWORD) &dwRet, 643 | NULL, 644 | NULL); 645 | if (err != 0) 646 | { 647 | DbgPrint("UdpProxy::setKeepAliveVals WSAIoctl err=%d", WSAGetLastError()); 648 | } 649 | } 650 | 651 | void onConnectComplete(SOCKET socket, DWORD dwTransferred, OV_DATA * pov, int error) 652 | { 653 | if (error != 0) 654 | { 655 | DbgPrint("UDPProxy::onConnectComplete %I64u failed, err=%d", pov->id, error); 656 | deleteProxyConnection(pov->id); 657 | deleteOV_DATA(pov); 658 | return; 659 | } 660 | 661 | { 662 | AutoLock lock(m_cs); 663 | 664 | tSocketMap::iterator it = m_socketMap.find(pov->id); 665 | if (it != m_socketMap.end()) 666 | { 667 | BOOL val = 1; 668 | setsockopt(socket, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0); 669 | setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*)&val, sizeof(val)); 670 | setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, (char*)&val, sizeof(val)); 671 | 672 | SOCKS5_AUTH_REQUEST authReq; 673 | 674 | authReq.version = SOCKS_5; 675 | authReq.nmethods = 1; 676 | 677 | if (!it->second->userName.empty()) 678 | { 679 | authReq.methods[0] = S5AM_UNPW; 680 | } else 681 | { 682 | authReq.methods[0] = S5AM_NONE; 683 | } 684 | 685 | if (startTcpSend(it->second->tcpSocket, (char*)&authReq, sizeof(authReq), pov->id)) 686 | { 687 | it->second->proxyState = PS_AUTH; 688 | } 689 | 690 | startTcpReceive(it->second->tcpSocket, pov->id, NULL); 691 | } 692 | } 693 | 694 | deleteOV_DATA(pov); 695 | } 696 | 697 | void onTcpSendComplete(SOCKET socket, DWORD dwTransferred, OV_DATA * pov, int error) 698 | { 699 | // DbgPrint("UDPProxy::onTcpSendComplete %I64u bytes=%d, err=%d", pov->id, dwTransferred, error); 700 | deleteOV_DATA(pov); 701 | } 702 | 703 | void onTcpReceiveComplete(SOCKET socket, DWORD dwTransferred, OV_DATA * pov, int error) 704 | { 705 | DbgPrint("UDPProxy::onTcpReceiveComplete %I64u bytes=%d, err=%d", pov->id, dwTransferred, error); 706 | 707 | if (dwTransferred == 0) 708 | { 709 | deleteOV_DATA(pov); 710 | return; 711 | } 712 | 713 | { 714 | AutoLock lock(m_cs); 715 | 716 | tSocketMap::iterator it = m_socketMap.find(pov->id); 717 | if (it != m_socketMap.end()) 718 | { 719 | switch (it->second->proxyState) 720 | { 721 | case PS_NONE: 722 | break; 723 | 724 | case PS_AUTH: 725 | { 726 | if (dwTransferred < sizeof(SOCK5_AUTH_RESPONSE)) 727 | break; 728 | 729 | SOCK5_AUTH_RESPONSE * pr = (SOCK5_AUTH_RESPONSE *)&pov->buffer[0]; 730 | 731 | if (pr->version != SOCKS_5) 732 | { 733 | break; 734 | } 735 | 736 | if (pr->method == S5AM_UNPW && !it->second->userName.empty()) 737 | { 738 | std::vector authReq; 739 | 740 | authReq.push_back(1); 741 | authReq.push_back((char)it->second->userName.length()); 742 | authReq.insert(authReq.end(), it->second->userName.begin(), it->second->userName.end()); 743 | authReq.push_back((char)it->second->userPassword.length()); 744 | 745 | if (!it->second->userPassword.empty()) 746 | authReq.insert(authReq.end(), it->second->userPassword.begin(), it->second->userPassword.end()); 747 | 748 | if (startTcpSend(it->second->tcpSocket, (char*)&authReq[0], (int)authReq.size(), pov->id)) 749 | { 750 | it->second->proxyState = PS_AUTH_NEGOTIATION; 751 | } 752 | 753 | break; 754 | } 755 | 756 | if (it->second->ipFamily == AF_INET) 757 | { 758 | SOCKS5_REQUEST_IPv4 req; 759 | 760 | req.version = SOCKS_5; 761 | req.command = S5C_UDP_ASSOCIATE; 762 | req.reserved = 0; 763 | req.address_type = SOCKS5_ADDR_IPV4; 764 | req.address = 0; 765 | req.port = 0; 766 | 767 | if (startTcpSend(it->second->tcpSocket, (char*)&req, sizeof(req), pov->id)) 768 | { 769 | it->second->proxyState = PS_UDP_ASSOC; 770 | } 771 | } else 772 | { 773 | SOCKS5_REQUEST_IPv6 req; 774 | 775 | memset(&req, 0, sizeof(req)); 776 | 777 | req.version = SOCKS_5; 778 | req.command = S5C_UDP_ASSOCIATE; 779 | req.address_type = SOCKS5_ADDR_IPV6; 780 | 781 | if (startTcpSend(it->second->tcpSocket, (char*)&req, sizeof(req), pov->id)) 782 | { 783 | it->second->proxyState = PS_UDP_ASSOC; 784 | } 785 | } 786 | } 787 | break; 788 | 789 | case PS_AUTH_NEGOTIATION: 790 | { 791 | if (dwTransferred < sizeof(SOCK5_AUTH_RESPONSE)) 792 | break; 793 | 794 | SOCK5_AUTH_RESPONSE * pr = (SOCK5_AUTH_RESPONSE *)&pov->buffer[0]; 795 | 796 | if (pr->version != 0x01 || pr->method != 0x00) 797 | { 798 | break; 799 | } 800 | 801 | if (it->second->ipFamily == AF_INET) 802 | { 803 | SOCKS5_REQUEST_IPv4 req; 804 | 805 | req.version = SOCKS_5; 806 | req.command = S5C_UDP_ASSOCIATE; 807 | req.reserved = 0; 808 | req.address_type = SOCKS5_ADDR_IPV4; 809 | req.address = 0; 810 | req.port = 0; 811 | 812 | if (startTcpSend(it->second->tcpSocket, (char*)&req, sizeof(req), pov->id)) 813 | { 814 | it->second->proxyState = PS_UDP_ASSOC; 815 | } 816 | } else 817 | { 818 | SOCKS5_REQUEST_IPv6 req; 819 | 820 | memset(&req, 0, sizeof(req)); 821 | req.version = SOCKS_5; 822 | req.command = S5C_UDP_ASSOCIATE; 823 | req.address_type = SOCKS5_ADDR_IPV6; 824 | 825 | if (startTcpSend(it->second->tcpSocket, (char*)&req, sizeof(req), pov->id)) 826 | { 827 | it->second->proxyState = PS_UDP_ASSOC; 828 | } 829 | } 830 | } 831 | break; 832 | 833 | case PS_UDP_ASSOC: 834 | { 835 | if (dwTransferred < sizeof(SOCKS5_RESPONSE)) 836 | break; 837 | 838 | SOCKS5_RESPONSE * pr = (SOCKS5_RESPONSE *)&pov->buffer[0]; 839 | 840 | if (pr->version != SOCKS_5 || pr->res_code != 0) 841 | break; 842 | 843 | if (pr->address_type == SOCKS5_ADDR_IPV4) 844 | { 845 | SOCKS5_RESPONSE_IPv4 * prIPv4 = (SOCKS5_RESPONSE_IPv4 *)&pov->buffer[0]; 846 | sockaddr_in addr; 847 | memset(&addr, 0, sizeof(addr)); 848 | addr.sin_family = AF_INET; 849 | addr.sin_addr.S_un.S_addr = ((sockaddr_in*)m_proxyAddress)->sin_addr.S_un.S_addr; 850 | addr.sin_port = prIPv4->port; 851 | 852 | memcpy(it->second->remoteAddress, &addr, sizeof(addr)); 853 | it->second->remoteAddressLen = sizeof(addr); 854 | } else 855 | if (pr->address_type == SOCKS5_ADDR_IPV6) 856 | { 857 | SOCKS5_RESPONSE_IPv6 * prIPv6 = (SOCKS5_RESPONSE_IPv6 *)&pov->buffer[0]; 858 | sockaddr_in6 addr; 859 | memset(&addr, 0, sizeof(addr)); 860 | addr.sin6_family = AF_INET6; 861 | memcpy(&addr.sin6_addr, &((sockaddr_in6*)m_proxyAddress)->sin6_addr, 16); 862 | addr.sin6_port = prIPv6->port; 863 | 864 | memcpy(it->second->remoteAddress, &addr, sizeof(addr)); 865 | it->second->remoteAddressLen = sizeof(addr); 866 | } else 867 | { 868 | break; 869 | } 870 | 871 | it->second->proxyState = PS_CONNECTED; 872 | 873 | while (!it->second->udpSendPackets.empty()) 874 | { 875 | tPacketList::iterator itp = it->second->udpSendPackets.begin(); 876 | 877 | udpSend(pov->id, &(*itp)->buffer[0], (int)(*itp)->buffer.size(), (*itp)->remoteAddress, (*itp)->remoteAddressLen); 878 | 879 | delete (*itp); 880 | it->second->udpSendPackets.erase(itp); 881 | } 882 | } 883 | break; 884 | } 885 | 886 | } 887 | } 888 | 889 | memset(&pov->ol, 0, sizeof(pov->ol)); 890 | 891 | startTcpReceive(socket, pov->id, pov); 892 | } 893 | 894 | 895 | virtual void onComplete(SOCKET socket, DWORD dwTransferred, OVERLAPPED * pOverlapped, int error) 896 | { 897 | OV_DATA * pov = (OV_DATA*)pOverlapped; 898 | 899 | switch (pov->type) 900 | { 901 | case OVT_UDP_SEND: 902 | onUdpSendComplete(socket, dwTransferred, pov, error); 903 | break; 904 | case OVT_UDP_RECEIVE: 905 | onUdpReceiveComplete(socket, dwTransferred, pov, error); 906 | break; 907 | case OVT_CONNECT: 908 | onConnectComplete(socket, dwTransferred, pov, error); 909 | break; 910 | case OVT_TCP_SEND: 911 | onTcpSendComplete(socket, dwTransferred, pov, error); 912 | break; 913 | case OVT_TCP_RECEIVE: 914 | onTcpReceiveComplete(socket, dwTransferred, pov, error); 915 | break; 916 | } 917 | } 918 | 919 | private: 920 | IOCPService m_service; 921 | UDPProxyHandler * m_pProxyHandler; 922 | 923 | tOvDataSet m_ovDataSet; 924 | tSocketMap m_socketMap; 925 | 926 | LPFN_CONNECTEX m_pConnectEx; 927 | 928 | char m_proxyAddress[NF_MAX_ADDRESS_LENGTH]; 929 | int m_proxyAddressLen; 930 | 931 | std::string m_userName; 932 | std::string m_userPassword; 933 | 934 | AutoCriticalSection m_cs; 935 | }; 936 | 937 | } -------------------------------------------------------------------------------- /src/dbglogger.h: -------------------------------------------------------------------------------- 1 | // 2 | // NetFilterSDK 3 | // Copyright (C) 2009 Vitaly Sidorov 4 | // All rights reserved. 5 | // 6 | // This file is a part of the NetFilter SDK. 7 | // The code and information is provided "as-is" without 8 | // warranty of any kind, either expressed or implied. 9 | // 10 | 11 | 12 | #if !defined(_DBGLOGGER_H) 13 | #define _DBGLOGGER_H 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include "sync.h" 23 | 24 | #pragma warning (disable:4996) 25 | 26 | using std::string; 27 | 28 | #if !defined(_DEBUG) && !defined(_RELEASE_LOG) 29 | #define DbgPrint 30 | #else 31 | #define DbgPrint DBGLogger::instance().writeInfo 32 | #endif 33 | 34 | class DBGLogger 35 | { 36 | public: 37 | 38 | virtual ~DBGLogger() 39 | { 40 | } 41 | 42 | void free() 43 | { 44 | { 45 | AutoLock lock(m_cs); 46 | if (!m_enabled) 47 | return; 48 | m_enabled = false; 49 | } 50 | if (m_hThread) 51 | { 52 | SetEvent(m_threadStop); 53 | 54 | WaitForSingleObject(m_hThread, INFINITE); 55 | 56 | CloseHandle(m_hThread); 57 | m_hThread = NULL; 58 | } 59 | } 60 | 61 | static DBGLogger dbgLog; 62 | 63 | static DBGLogger& instance() 64 | { 65 | return dbgLog; 66 | } 67 | 68 | void init(const std::string & sFileName) 69 | { 70 | AutoLock cs(m_cs); 71 | 72 | m_sFileName = sFileName; 73 | m_enabled = true; 74 | 75 | ResetEvent(m_threadStop); 76 | m_hThread = (HANDLE)_beginthreadex(0, 0, 77 | _workerThread, 78 | (LPVOID)this, 79 | 0, 80 | NULL); 81 | if (m_hThread == (HANDLE)(-1L)) 82 | { 83 | m_hThread = NULL; 84 | } 85 | } 86 | 87 | void writeInfo(const char* sMessage, ...) 88 | { 89 | int nSize = BUFSIZ; 90 | string sBuffer; 91 | va_list args; 92 | 93 | va_start(args, sMessage); 94 | { 95 | do 96 | { 97 | sBuffer.resize(nSize); 98 | memset(&sBuffer[0], 0, sBuffer.length()); 99 | 100 | int nResult = _vsnprintf(const_cast(sBuffer.data()), 101 | sBuffer.length(), sMessage, args); 102 | 103 | if (nResult < 0) 104 | { 105 | nSize *= 2; 106 | } 107 | else 108 | { 109 | sBuffer.resize(nResult); 110 | 111 | sBuffer = getTime() + string(": ") + sBuffer + string("\r\n"); 112 | 113 | break; 114 | } 115 | } 116 | while (nSize); 117 | } 118 | va_end(args); 119 | 120 | { 121 | AutoLock cs(m_cs); 122 | if (!m_enabled) 123 | { 124 | return; 125 | } 126 | m_logQueue.push(sBuffer); 127 | } 128 | 129 | SetEvent(m_threadWake); 130 | } 131 | 132 | 133 | string generateFileName(string sName) const 134 | { 135 | size_t nSize = MAX_PATH; 136 | string sPath; 137 | 138 | do 139 | { 140 | sPath.resize(nSize); 141 | 142 | nSize = GetModuleFileName(NULL, 143 | const_cast(sPath.data()), 144 | (DWORD)(sPath.length() - 1)); 145 | 146 | if (nSize >= sPath.length() - 2) 147 | { 148 | nSize *= 2; 149 | } 150 | else 151 | { 152 | sPath.resize(nSize); 153 | 154 | size_t nIndex = sPath.rfind("\\"); 155 | if (nIndex != string::npos && nIndex > 0) 156 | { 157 | sPath.resize(nIndex); 158 | } 159 | else 160 | { 161 | sPath = ""; 162 | } 163 | 164 | break; 165 | } 166 | } 167 | while (nSize); 168 | 169 | SYSTEMTIME systemTime; 170 | 171 | GetSystemTime(&systemTime); 172 | 173 | char sValue[BUFSIZ]; 174 | 175 | string sFileName = sName; 176 | 177 | if (systemTime.wMonth < 10) 178 | { 179 | sFileName += "0"; 180 | } 181 | 182 | _ltoa(systemTime.wMonth, sValue, 10); 183 | sFileName += sValue; 184 | 185 | if (systemTime.wDay < 10) 186 | { 187 | sFileName += "0"; 188 | } 189 | _ltoa(systemTime.wDay, sValue, 10); 190 | sFileName += sValue; 191 | 192 | _ltoa(systemTime.wYear, sValue, 10); 193 | sFileName += sValue; 194 | 195 | sFileName += "-"; 196 | 197 | for (size_t i = 0;;i++) 198 | { 199 | WIN32_FIND_DATA findFileData; 200 | HANDLE hFind; 201 | char sValue[BUFSIZ]; 202 | string sTempName = sFileName; 203 | 204 | _ltoa((long)i, sValue, 10); 205 | 206 | sTempName += sValue; 207 | sTempName += ".lst"; 208 | 209 | sTempName = sPath + string("\\") + sTempName; 210 | 211 | hFind = FindFirstFile(sTempName.c_str(), &findFileData); 212 | if (hFind == INVALID_HANDLE_VALUE) 213 | { 214 | sFileName = sTempName; 215 | 216 | break; 217 | } 218 | else 219 | { 220 | FindClose(hFind); 221 | } 222 | } 223 | 224 | return sFileName; 225 | } 226 | 227 | string getTime() const 228 | { 229 | string sTime; 230 | time_t tNow = time(NULL); 231 | struct tm* ptm = localtime(&tNow); 232 | 233 | if (ptm != NULL) 234 | { 235 | sTime = asctime(ptm); 236 | 237 | size_t nIndex = sTime.find_first_of("\r\n"); 238 | if (nIndex != string::npos) 239 | { 240 | sTime.resize(nIndex); 241 | } 242 | } 243 | 244 | return sTime; 245 | } 246 | 247 | private: 248 | bool m_enabled; 249 | FILE * m_pFile; 250 | string m_sFileName; 251 | typedef std::queue tLogQueue; 252 | tLogQueue m_logQueue; 253 | HANDLE m_hThread; 254 | AutoEventHandle m_threadStop; 255 | AutoEventHandle m_threadWake; 256 | AutoCriticalSection m_cs; 257 | 258 | DBGLogger() : m_enabled(false), m_pFile(NULL), m_hThread(NULL) 259 | { 260 | } 261 | 262 | static unsigned WINAPI _workerThread(void* pData) 263 | { 264 | ((DBGLogger*)pData)->workerThread(); 265 | return 0; 266 | } 267 | 268 | void workerThread() 269 | { 270 | HANDLE events[] = { m_threadStop, m_threadWake }; 271 | 272 | FILE* pFile = NULL; 273 | 274 | pFile = open(); 275 | if (!pFile) 276 | return; 277 | 278 | bool fExitLoop = false; 279 | 280 | for (;;) 281 | { 282 | if (fExitLoop) 283 | { 284 | break; 285 | } 286 | 287 | DWORD res = WaitForMultipleObjects(2, events, FALSE, 5000); 288 | if (res == WAIT_OBJECT_0) 289 | { 290 | fExitLoop = true; 291 | } 292 | 293 | for (;;) 294 | { 295 | std::string sBuffer; 296 | 297 | { 298 | AutoLock lock(m_cs); 299 | 300 | if (m_logQueue.empty()) 301 | break; 302 | 303 | sBuffer = m_logQueue.front(); 304 | m_logQueue.pop(); 305 | } 306 | 307 | if (pFile) 308 | { 309 | fwrite(sBuffer.c_str(), sizeof(char), sBuffer.length(), pFile); 310 | fflush(pFile); 311 | } 312 | } 313 | } 314 | 315 | { 316 | AutoLock lock(m_cs); 317 | 318 | while( !m_logQueue.empty() ) 319 | { 320 | m_logQueue.pop(); 321 | } 322 | } 323 | 324 | close(); 325 | } 326 | 327 | 328 | FILE* open() 329 | { 330 | if (m_pFile) 331 | return m_pFile; 332 | 333 | m_pFile = fopen(m_sFileName.c_str(), "ab"); 334 | if (m_pFile == NULL) 335 | { 336 | m_pFile = fopen(m_sFileName.c_str(), "wb"); 337 | } 338 | 339 | return m_pFile; 340 | } 341 | 342 | void close() 343 | { 344 | if (m_pFile != NULL) 345 | { 346 | fclose(m_pFile); 347 | m_pFile = NULL; 348 | } 349 | } 350 | }; 351 | 352 | 353 | #endif // !defined(_DBGLOGGER_H) 354 | -------------------------------------------------------------------------------- /src/icmp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "nfapi.h" 5 | 6 | using namespace nfapi; 7 | 8 | DWORD delay; 9 | 10 | class IPEventHandler : public NF_IPEventHandler 11 | { 12 | public: 13 | unsigned short checksum(unsigned char* buf, unsigned int len) 14 | { 15 | unsigned int sum = 0; 16 | unsigned int cnt = len; 17 | for (unsigned int i = 0; i < len; i += 2) 18 | { 19 | sum += (buf[i] << 8) + buf[i + 1]; 20 | cnt -= 2; 21 | } 22 | if (cnt == 1) 23 | { 24 | sum += buf[len - 1] << 8; 25 | } 26 | while (sum >> 16) 27 | { 28 | sum = (sum >> 16) + (sum & 0xffff); 29 | } 30 | return (unsigned short)~sum; 31 | } 32 | 33 | virtual void ipSend(const char* buf, int len, PNF_IP_PACKET_OPTIONS options) 34 | { 35 | if (options->ip_family == AF_INET && options->ipHeaderSize == 20 && len >= 28 && 36 | buf[0] == 69 && buf[9] == 1 && buf[20] == 8 && buf[21] == 0) 37 | { 38 | unsigned char* data = new unsigned char[len]; 39 | memcpy(data, buf, len); 40 | unsigned char src[4]; 41 | memcpy(src, &data[12], 4); 42 | memcpy(&data[12], &data[16], 4); 43 | memcpy(&data[16], src, 4); 44 | unsigned short sum = checksum(data, 20); 45 | data[10] = (sum >> 8); 46 | data[11] = sum & 0xff; 47 | data[20] = 0; 48 | data[22] += 8; 49 | if (data[22] < 8) data[23] += 1; 50 | if (delay > 0) std::this_thread::sleep_for(std::chrono::milliseconds(delay)); 51 | printf("ipSend %d.%d.%d.%d\n", data[12], data[13], data[14], data[15]); 52 | nf_ipPostReceive((char*)data, len, options); 53 | return; 54 | } 55 | if (options->ip_family == AF_INET6 && options->ipHeaderSize == 40 && len >= 48 && 56 | buf[0] >> 4 == 6 && buf[40] == -128 && buf[41] == 0) 57 | { 58 | unsigned char* data = new unsigned char[len]; 59 | memcpy(data, buf, len); 60 | unsigned char src[16]; 61 | memcpy(src, &data[8], 16); 62 | memcpy(&data[8], &data[24], 16); 63 | memcpy(&data[24], src, 16); 64 | data[40] = 129; 65 | data[42] -= 1; 66 | if (data[42] == 255) data[43] -= 1; 67 | if (delay > 0) std::this_thread::sleep_for(std::chrono::milliseconds(delay)); 68 | printf("ipSend %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x\n", 69 | data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15], 70 | data[16], data[17], data[18], data[19], data[20], data[21], data[22], data[23]); 71 | nf_ipPostReceive((char*)data, len, options); 72 | return; 73 | } 74 | nf_ipPostSend(buf, len, options); 75 | } 76 | virtual void ipReceive(const char* buf, int len, PNF_IP_PACKET_OPTIONS options) 77 | { 78 | nf_ipPostReceive(buf, len, options); 79 | } 80 | }; 81 | -------------------------------------------------------------------------------- /src/iocp.h: -------------------------------------------------------------------------------- 1 | // 2 | // NetFilterSDK 3 | // Copyright (C) Vitaly Sidorov 4 | // All rights reserved. 5 | // 6 | // This file is a part of the NetFilter SDK. 7 | // The code and information is provided "as-is" without 8 | // warranty of any kind, either expressed or implied. 9 | // 10 | 11 | #pragma once 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "sync.h" 18 | #include "socksdefs.h" 19 | 20 | class IOCPHandler 21 | { 22 | public: 23 | virtual void onComplete(SOCKET socket, DWORD dwTransferred, OVERLAPPED * pOverlapped, int error) = 0; 24 | }; 25 | 26 | class IOCPService 27 | { 28 | public: 29 | IOCPService() : m_hIOCP(INVALID_HANDLE_VALUE), m_pHandler(NULL) 30 | { 31 | } 32 | ~IOCPService() 33 | { 34 | } 35 | 36 | bool init(IOCPHandler * pHandler) 37 | { 38 | m_pHandler = pHandler; 39 | 40 | if (m_hIOCP != INVALID_HANDLE_VALUE) 41 | return false; 42 | 43 | m_hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 0); 44 | if (m_hIOCP == INVALID_HANDLE_VALUE) 45 | return false; 46 | 47 | ResetEvent(m_stopEvent); 48 | 49 | HANDLE hThread = (HANDLE)_beginthreadex(0, 0, 50 | _workerThread, 51 | (LPVOID)this, 52 | 0, 53 | NULL); 54 | 55 | if (hThread != 0) 56 | { 57 | m_workerThread.Attach(hThread); 58 | } 59 | 60 | return true; 61 | } 62 | 63 | void free() 64 | { 65 | if (m_workerThread == INVALID_HANDLE_VALUE) 66 | return; 67 | 68 | SetEvent(m_stopEvent); 69 | WaitForSingleObject(m_workerThread, INFINITE); 70 | m_workerThread.Close(); 71 | 72 | if (m_hIOCP != INVALID_HANDLE_VALUE) 73 | { 74 | CloseHandle(m_hIOCP); 75 | m_hIOCP = INVALID_HANDLE_VALUE; 76 | } 77 | } 78 | 79 | bool registerSocket(SOCKET s) 80 | { 81 | if (!CreateIoCompletionPort((HANDLE)s, m_hIOCP, (ULONG_PTR)s, 1)) 82 | return false; 83 | 84 | return true; 85 | } 86 | 87 | bool postCompletion(SOCKET s, DWORD dwTransferred, LPOVERLAPPED pol) 88 | { 89 | return PostQueuedCompletionStatus(m_hIOCP, dwTransferred, (ULONG_PTR)s, pol)? true : false; 90 | } 91 | 92 | protected: 93 | 94 | void workerThread() 95 | { 96 | DWORD dwTransferred; 97 | ULONG_PTR cKey; 98 | OVERLAPPED * pOverlapped; 99 | 100 | for (;;) 101 | { 102 | if (GetQueuedCompletionStatus(m_hIOCP, &dwTransferred, &cKey, &pOverlapped, 500)) 103 | { 104 | m_pHandler->onComplete((SOCKET)cKey, dwTransferred, pOverlapped, 0); 105 | } else 106 | { 107 | DWORD err = GetLastError(); 108 | if (err != WAIT_TIMEOUT) 109 | { 110 | m_pHandler->onComplete((SOCKET)cKey, dwTransferred, pOverlapped, err); 111 | } 112 | } 113 | 114 | if (WaitForSingleObject(m_stopEvent, 0) == WAIT_OBJECT_0) 115 | break; 116 | } 117 | 118 | } 119 | 120 | static unsigned int WINAPI _workerThread(void * pThis) 121 | { 122 | ((IOCPService*)pThis)->workerThread(); 123 | return 0; 124 | } 125 | 126 | private: 127 | 128 | HANDLE m_hIOCP; 129 | AutoEventHandle m_stopEvent; 130 | AutoHandle m_workerThread; 131 | IOCPHandler * m_pHandler; 132 | }; 133 | 134 | -------------------------------------------------------------------------------- /src/linkedlist.h: -------------------------------------------------------------------------------- 1 | // 2 | // NetFilterSDK 3 | // Copyright (C) Vitaly Sidorov 4 | // All rights reserved. 5 | // 6 | // This file is a part of the NetFilter SDK. 7 | // The code and information is provided "as-is" without 8 | // warranty of any kind, either expressed or implied. 9 | // 10 | 11 | #ifndef _LINKED_LIST 12 | 13 | // 14 | // Calculate the address of the base of the structure given its type, and an 15 | // address of a field within the structure. 16 | // 17 | #ifndef CONTAINING_RECORD 18 | #define CONTAINING_RECORD(address, type, field) \ 19 | ((type *)((PCHAR)(address) - (ULONG_PTR)(&((type *)0)->field))) 20 | #endif 21 | 22 | // 23 | // VOID 24 | // InitializeListHead( 25 | // PLIST_ENTRY ListHead 26 | // ); 27 | // 28 | 29 | #define InitializeListHead(ListHead) (\ 30 | (ListHead)->Flink = (ListHead)->Blink = (ListHead)) 31 | 32 | // 33 | // BOOLEAN 34 | // IsListEmpty( 35 | // PLIST_ENTRY ListHead 36 | // ); 37 | // 38 | 39 | #define IsListEmpty(ListHead) \ 40 | ((ListHead)->Flink == (ListHead)) 41 | 42 | // 43 | // PLIST_ENTRY 44 | // RemoveHeadList( 45 | // PLIST_ENTRY ListHead 46 | // ); 47 | // 48 | 49 | #define RemoveHeadList(ListHead) \ 50 | (ListHead)->Flink;\ 51 | {RemoveEntryList((ListHead)->Flink)} 52 | 53 | // 54 | // PLIST_ENTRY 55 | // RemoveTailList( 56 | // PLIST_ENTRY ListHead 57 | // ); 58 | // 59 | 60 | #define RemoveTailList(ListHead) \ 61 | (ListHead)->Blink;\ 62 | {RemoveEntryList((ListHead)->Blink)} 63 | 64 | // 65 | // VOID 66 | // RemoveEntryList( 67 | // PLIST_ENTRY Entry 68 | // ); 69 | // 70 | 71 | #define RemoveEntryList(Entry) {\ 72 | PLIST_ENTRY _EX_Blink;\ 73 | PLIST_ENTRY _EX_Flink;\ 74 | _EX_Flink = (Entry)->Flink;\ 75 | _EX_Blink = (Entry)->Blink;\ 76 | _EX_Blink->Flink = _EX_Flink;\ 77 | _EX_Flink->Blink = _EX_Blink;\ 78 | } 79 | 80 | // 81 | // VOID 82 | // InsertTailList( 83 | // PLIST_ENTRY ListHead, 84 | // PLIST_ENTRY Entry 85 | // ); 86 | // 87 | 88 | #define InsertTailList(ListHead,Entry) {\ 89 | PLIST_ENTRY _EX_Blink;\ 90 | PLIST_ENTRY _EX_ListHead;\ 91 | _EX_ListHead = (ListHead);\ 92 | _EX_Blink = _EX_ListHead->Blink;\ 93 | (Entry)->Flink = _EX_ListHead;\ 94 | (Entry)->Blink = _EX_Blink;\ 95 | _EX_Blink->Flink = (Entry);\ 96 | _EX_ListHead->Blink = (Entry);\ 97 | } 98 | 99 | // 100 | // VOID 101 | // InsertHeadList( 102 | // PLIST_ENTRY ListHead, 103 | // PLIST_ENTRY Entry 104 | // ); 105 | // 106 | 107 | #define InsertHeadList(ListHead,Entry) {\ 108 | PLIST_ENTRY _EX_Flink;\ 109 | PLIST_ENTRY _EX_ListHead;\ 110 | _EX_ListHead = (ListHead);\ 111 | _EX_Flink = _EX_ListHead->Flink;\ 112 | (Entry)->Flink = _EX_Flink;\ 113 | (Entry)->Blink = _EX_ListHead;\ 114 | _EX_Flink->Blink = (Entry);\ 115 | _EX_ListHead->Flink = (Entry);\ 116 | } 117 | 118 | 119 | #endif //_LINKED_LIST 120 | -------------------------------------------------------------------------------- /src/socksdefs.h: -------------------------------------------------------------------------------- 1 | // 2 | // NetFilterSDK 3 | // Copyright (C) Vitaly Sidorov 4 | // All rights reserved. 5 | // 6 | // This file is a part of the NetFilter SDK. 7 | // The code and information is provided "as-is" without 8 | // warranty of any kind, either expressed or implied. 9 | // 10 | 11 | #pragma once 12 | 13 | #pragma pack(push, 1) 14 | 15 | enum eSOCKS_VERSION 16 | { 17 | SOCKS_4 = 4, 18 | SOCKS_5 = 5 19 | }; 20 | 21 | enum eSOCKS4_COMMAND 22 | { 23 | S4C_CONNECT = 1, 24 | S4C_BIND = 2 25 | }; 26 | 27 | struct SOCKS4_REQUEST 28 | { 29 | char version; 30 | char command; 31 | unsigned short port; 32 | unsigned int ip; 33 | char userid[1]; 34 | }; 35 | 36 | enum eSOCKS4_RESCODE 37 | { 38 | S4RC_SUCCESS = 0x5a 39 | }; 40 | 41 | struct SOCKS4_RESPONSE 42 | { 43 | char reserved; 44 | char res_code; 45 | unsigned short port; 46 | unsigned int ip; 47 | }; 48 | 49 | enum eSOCKS5_COMMAND 50 | { 51 | S5C_AUTH = -1, 52 | S5C_CONNECT = 1, 53 | S5C_BIND = 2, 54 | S5C_UDP_ASSOCIATE = 3 55 | }; 56 | 57 | struct SOCKS5_AUTH_REQUEST 58 | { 59 | char version; 60 | unsigned char nmethods; 61 | unsigned char methods[1]; 62 | }; 63 | 64 | enum eSOCKS5_AUTH_METHOD 65 | { 66 | S5AM_NONE = 0, 67 | S5AM_GSSAPI = 1, 68 | S5AM_UNPW = 2 69 | }; 70 | 71 | struct SOCK5_AUTH_RESPONSE 72 | { 73 | char version; 74 | unsigned char method; 75 | }; 76 | 77 | enum eSOCKS5_ADDRESS_TYPE 78 | { 79 | SOCKS5_ADDR_IPV4 = 1, 80 | SOCKS5_ADDR_DOMAIN = 3, 81 | SOCKS5_ADDR_IPV6 = 4 82 | }; 83 | 84 | struct SOCKS5_REQUEST 85 | { 86 | char version; 87 | char command; 88 | char reserved; 89 | char address_type; 90 | char address[1]; 91 | }; 92 | 93 | struct SOCKS5_REQUEST_IPv4 94 | { 95 | char version; 96 | char command; 97 | char reserved; 98 | char address_type; 99 | unsigned int address; 100 | unsigned short port; 101 | }; 102 | 103 | struct SOCKS5_REQUEST_IPv6 104 | { 105 | char version; 106 | char command; 107 | char reserved; 108 | char address_type; 109 | char address[16]; 110 | unsigned short port; 111 | }; 112 | 113 | struct SOCKS5_RESPONSE 114 | { 115 | char version; 116 | char res_code; 117 | char reserved; 118 | char address_type; 119 | char address[1]; 120 | }; 121 | 122 | struct SOCKS5_RESPONSE_IPv4 123 | { 124 | char version; 125 | char res_code; 126 | char reserved; 127 | char address_type; 128 | unsigned int address; 129 | unsigned short port; 130 | }; 131 | 132 | struct SOCKS5_RESPONSE_IPv6 133 | { 134 | char version; 135 | char res_code; 136 | char reserved; 137 | char address_type; 138 | char address[16]; 139 | unsigned short port; 140 | }; 141 | 142 | struct SOCKS5_UDP_REQUEST 143 | { 144 | unsigned short reserved; 145 | char frag; 146 | char address_type; 147 | }; 148 | 149 | struct SOCKS5_UDP_REQUEST_IPv4 150 | { 151 | unsigned short reserved; 152 | char frag; 153 | char address_type; 154 | unsigned int address; 155 | unsigned short port; 156 | }; 157 | 158 | struct SOCKS5_UDP_REQUEST_IPv6 159 | { 160 | unsigned short reserved; 161 | char frag; 162 | char address_type; 163 | char address[16]; 164 | unsigned short port; 165 | }; 166 | 167 | union SOCKS45_REQUEST 168 | { 169 | SOCKS4_REQUEST socks4_req; 170 | SOCKS5_AUTH_REQUEST socks5_auth_req; 171 | SOCKS5_REQUEST socks5_req; 172 | }; 173 | 174 | #pragma pack(pop) 175 | 176 | -------------------------------------------------------------------------------- /src/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // PassThrough.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /src/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later. 9 | #define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows. 10 | #endif 11 | 12 | #define _CRT_SECURE_NO_DEPRECATE 1 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "dbglogger.h" 19 | -------------------------------------------------------------------------------- /src/sync.h: -------------------------------------------------------------------------------- 1 | // 2 | // NetFilterSDK 3 | // Copyright (C) Vitaly Sidorov 4 | // All rights reserved. 5 | // 6 | // This file is a part of the NetFilter SDK. 7 | // The code and information is provided "as-is" without 8 | // warranty of any kind, either expressed or implied. 9 | // 10 | 11 | #ifndef _SYNC_H 12 | #define _SYNC_H 13 | 14 | class CriticalSection 15 | { 16 | public: 17 | CriticalSection() throw() 18 | { 19 | memset(&m_sec, 0, sizeof(CRITICAL_SECTION)); 20 | } 21 | ~CriticalSection() 22 | { 23 | } 24 | HRESULT Lock() throw() 25 | { 26 | EnterCriticalSection(&m_sec); 27 | return S_OK; 28 | } 29 | HRESULT Unlock() throw() 30 | { 31 | LeaveCriticalSection(&m_sec); 32 | return S_OK; 33 | } 34 | HRESULT Init() throw() 35 | { 36 | HRESULT hRes = E_FAIL; 37 | __try 38 | { 39 | InitializeCriticalSection(&m_sec); 40 | hRes = S_OK; 41 | } 42 | // structured exception may be raised in low memory situations 43 | __except(STATUS_NO_MEMORY == GetExceptionCode()) 44 | { 45 | hRes = E_OUTOFMEMORY; 46 | } 47 | return hRes; 48 | } 49 | 50 | HRESULT Term() throw() 51 | { 52 | DeleteCriticalSection(&m_sec); 53 | return S_OK; 54 | } 55 | CRITICAL_SECTION m_sec; 56 | }; 57 | 58 | class AutoCriticalSection : public CriticalSection 59 | { 60 | public: 61 | AutoCriticalSection() 62 | { 63 | CriticalSection::Init(); 64 | } 65 | ~AutoCriticalSection() throw() 66 | { 67 | CriticalSection::Term(); 68 | } 69 | private : 70 | HRESULT Init(); 71 | HRESULT Term(); 72 | }; 73 | 74 | class AutoLock 75 | { 76 | public: 77 | AutoLock(AutoCriticalSection& cs) : m_cs(cs) 78 | { 79 | m_cs.Lock(); 80 | } 81 | 82 | virtual ~AutoLock() 83 | { 84 | m_cs.Unlock(); 85 | } 86 | 87 | private: 88 | AutoCriticalSection& m_cs; 89 | }; 90 | 91 | class AutoUnlock 92 | { 93 | public: 94 | AutoUnlock(AutoCriticalSection& cs) : m_cs(cs) 95 | { 96 | m_cs.Unlock(); 97 | } 98 | 99 | virtual ~AutoUnlock() 100 | { 101 | m_cs.Lock(); 102 | } 103 | 104 | private: 105 | AutoCriticalSection& m_cs; 106 | }; 107 | 108 | class AutoHandle 109 | { 110 | public: 111 | AutoHandle() throw(); 112 | AutoHandle( AutoHandle& h ) throw(); 113 | explicit AutoHandle( HANDLE h ) throw(); 114 | ~AutoHandle() throw(); 115 | 116 | AutoHandle& operator=( AutoHandle& h ) throw(); 117 | 118 | operator HANDLE() const throw(); 119 | 120 | // Attach to an existing handle (takes ownership). 121 | void Attach( HANDLE h ) throw(); 122 | // Detach the handle from the object (releases ownership). 123 | HANDLE Detach() throw(); 124 | 125 | // Close the handle. 126 | void Close() throw(); 127 | 128 | public: 129 | HANDLE m_h; 130 | }; 131 | 132 | inline AutoHandle::AutoHandle() throw() : 133 | m_h( INVALID_HANDLE_VALUE ) 134 | { 135 | } 136 | 137 | inline AutoHandle::AutoHandle( AutoHandle& h ) throw() : 138 | m_h( INVALID_HANDLE_VALUE ) 139 | { 140 | Attach( h.Detach() ); 141 | } 142 | 143 | inline AutoHandle::AutoHandle( HANDLE h ) throw() : 144 | m_h( h ) 145 | { 146 | } 147 | 148 | inline AutoHandle::~AutoHandle() throw() 149 | { 150 | if( m_h != INVALID_HANDLE_VALUE ) 151 | { 152 | Close(); 153 | } 154 | } 155 | 156 | inline AutoHandle& AutoHandle::operator=( AutoHandle& h ) throw() 157 | { 158 | if( this != &h ) 159 | { 160 | if( m_h != INVALID_HANDLE_VALUE ) 161 | { 162 | Close(); 163 | } 164 | Attach( h.Detach() ); 165 | } 166 | 167 | return( *this ); 168 | } 169 | 170 | inline AutoHandle::operator HANDLE() const throw() 171 | { 172 | return( m_h ); 173 | } 174 | 175 | inline void AutoHandle::Attach( HANDLE h ) throw() 176 | { 177 | m_h = h; // Take ownership 178 | } 179 | 180 | inline HANDLE AutoHandle::Detach() throw() 181 | { 182 | HANDLE h; 183 | 184 | h = m_h; // Release ownership 185 | m_h = INVALID_HANDLE_VALUE; 186 | 187 | return( h ); 188 | } 189 | 190 | inline void AutoHandle::Close() throw() 191 | { 192 | if( m_h != INVALID_HANDLE_VALUE ) 193 | { 194 | ::CloseHandle( m_h ); 195 | m_h = INVALID_HANDLE_VALUE; 196 | } 197 | } 198 | 199 | class AutoEventHandle : public AutoHandle 200 | { 201 | public: 202 | AutoEventHandle() 203 | { 204 | m_h = CreateEvent(NULL, FALSE, FALSE, NULL); 205 | } 206 | ~AutoEventHandle() 207 | { 208 | Close(); 209 | } 210 | }; 211 | 212 | class AutoEventHandleM : public AutoHandle 213 | { 214 | public: 215 | AutoEventHandleM() 216 | { 217 | m_h = CreateEvent(NULL, TRUE, FALSE, NULL); 218 | } 219 | ~AutoEventHandleM() 220 | { 221 | Close(); 222 | } 223 | }; 224 | 225 | #endif -------------------------------------------------------------------------------- /src/tcpproxy.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // NetFilterSDK 4 | // Copyright (C) Vitaly Sidorov 5 | // All rights reserved. 6 | // 7 | // This file is a part of the NetFilter SDK. 8 | // The code and information is provided "as-is" without 9 | // warranty of any kind, either expressed or implied. 10 | // 11 | 12 | #pragma once 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "sync.h" 20 | #include "linkedlist.h" 21 | #include "socksdefs.h" 22 | #include "iocp.h" 23 | #include "threadpool.h" 24 | #include "nfevents.h" 25 | #include "DbgLogger.h" 26 | 27 | namespace TcpProxy 28 | { 29 | 30 | #define TCP_PACKET_SIZE 8192 31 | #define IN_SOCKET true 32 | #define OUT_SOCKET false 33 | 34 | struct TCP_PACKET 35 | { 36 | TCP_PACKET() 37 | { 38 | buffer.len = 0; 39 | buffer.buf = NULL; 40 | } 41 | TCP_PACKET(const char * buf, int len) 42 | { 43 | if (len > 0) 44 | { 45 | buffer.buf = new char[len]; 46 | buffer.len = len; 47 | 48 | if (buf) 49 | { 50 | memcpy(buffer.buf, buf, len); 51 | } 52 | } else 53 | { 54 | buffer.buf = NULL; 55 | buffer.len = 0; 56 | } 57 | } 58 | 59 | WSABUF & operator ()() 60 | { 61 | return buffer; 62 | } 63 | 64 | void free() 65 | { 66 | if (buffer.buf) 67 | { 68 | delete[] buffer.buf; 69 | } 70 | } 71 | 72 | WSABUF buffer; 73 | }; 74 | 75 | typedef std::vector tPacketList; 76 | 77 | enum OV_TYPE 78 | { 79 | OVT_ACCEPT, 80 | OVT_CONNECT, 81 | OVT_CLOSE, 82 | OVT_SEND, 83 | OVT_RECEIVE 84 | }; 85 | 86 | struct OV_DATA 87 | { 88 | OV_DATA() 89 | { 90 | memset(&ol, 0, sizeof(ol)); 91 | } 92 | ~OV_DATA() 93 | { 94 | for (tPacketList::iterator it = packetList.begin(); it != packetList.end(); it++) 95 | { 96 | it->free(); 97 | } 98 | } 99 | 100 | OVERLAPPED ol; 101 | LIST_ENTRY entry; 102 | LIST_ENTRY entryEventList; 103 | NFAPI_NS ENDPOINT_ID id; 104 | OV_TYPE type; 105 | tPacketList packetList; 106 | 107 | SOCKET socket; 108 | DWORD dwTransferred; 109 | int error; 110 | }; 111 | 112 | enum PROXY_STATE 113 | { 114 | PS_NONE, 115 | PS_AUTH, 116 | PS_AUTH_NEGOTIATION, 117 | PS_CONNECT, 118 | PS_CONNECTED, 119 | PS_ERROR, 120 | PS_CLOSED 121 | }; 122 | 123 | enum PROXY_TYPE 124 | { 125 | PROXY_NONE, 126 | PROXY_SOCKS5 127 | }; 128 | 129 | struct SOCKET_DATA 130 | { 131 | SOCKET_DATA() 132 | { 133 | socket = INVALID_SOCKET; 134 | disconnected = false; 135 | receiveInProgress = false; 136 | sendInProgress = false; 137 | disconnect = false; 138 | closed = false; 139 | } 140 | ~SOCKET_DATA() 141 | { 142 | if (socket != INVALID_SOCKET) 143 | { 144 | closesocket(socket); 145 | } 146 | for (tPacketList::iterator it = packetList.begin(); it != packetList.end(); it++) 147 | { 148 | it->free(); 149 | } 150 | } 151 | 152 | SOCKET socket; 153 | bool disconnected; 154 | bool receiveInProgress; 155 | bool sendInProgress; 156 | bool disconnect; 157 | bool closed; 158 | tPacketList packetList; 159 | }; 160 | 161 | struct PROXY_DATA 162 | { 163 | PROXY_DATA() 164 | { 165 | id = 0; 166 | proxyState = PS_NONE; 167 | suspended = false; 168 | offline = false; 169 | memset(&connInfo, 0, sizeof(connInfo)); 170 | refCount = 1; 171 | proxyType = PROXY_NONE; 172 | proxyAddressLen = 0; 173 | } 174 | ~PROXY_DATA() 175 | { 176 | } 177 | 178 | NFAPI_NS ENDPOINT_ID id; 179 | 180 | SOCKET_DATA inSocket; 181 | SOCKET_DATA outSocket; 182 | 183 | PROXY_STATE proxyState; 184 | NFAPI_NS NF_TCP_CONN_INFO connInfo; 185 | 186 | PROXY_TYPE proxyType; 187 | char proxyAddress[NF_MAX_ADDRESS_LENGTH]; 188 | int proxyAddressLen; 189 | 190 | std::string userName; 191 | std::string userPassword; 192 | 193 | bool suspended; 194 | bool offline; 195 | 196 | int refCount; 197 | AutoCriticalSection lock; 198 | 199 | private: 200 | PROXY_DATA & operator = (const PROXY_DATA & v) 201 | { 202 | return *this; 203 | } 204 | 205 | }; 206 | 207 | class TCPProxy : public IOCPHandler, public ThreadJobSource 208 | { 209 | public: 210 | TCPProxy() 211 | { 212 | m_listenSocket = INVALID_SOCKET; 213 | m_acceptSocket = INVALID_SOCKET; 214 | m_listenSocket_IPv6 = INVALID_SOCKET; 215 | m_acceptSocket_IPv6 = INVALID_SOCKET; 216 | m_port = 0; 217 | m_pPFEventHandler = NULL; 218 | m_ipv4Available = false; 219 | m_ipv6Available = false; 220 | m_proxyType = PROXY_NONE; 221 | m_proxyAddressLen = 0; 222 | } 223 | 224 | virtual ~TCPProxy() 225 | { 226 | } 227 | 228 | unsigned short getPort() 229 | { 230 | return m_port; 231 | } 232 | 233 | bool isIPFamilyAvailable(int ipFamily) 234 | { 235 | switch (ipFamily) 236 | { 237 | case AF_INET: 238 | return m_ipv4Available; 239 | case AF_INET6: 240 | return m_ipv6Available; 241 | } 242 | return false; 243 | } 244 | 245 | bool init(unsigned short port, bool bindToLocalhost = true, int threadCount = 0) 246 | { 247 | bool result = false; 248 | 249 | DbgPrint("TCPProxy::init port=%d", htons(port)); 250 | 251 | m_timeout = 5 * 60 * 1000; 252 | 253 | InitializeListHead(&m_ovDataList); 254 | m_ovDataCounter = 0; 255 | 256 | InitializeListHead(&m_eventList); 257 | 258 | m_port = port; 259 | 260 | m_connId = 0; 261 | 262 | if (!initExtensions()) 263 | { 264 | DbgPrint("TCPProxy::init initExtensions() failed"); 265 | return false; 266 | } 267 | 268 | for (;;) 269 | { 270 | if (!m_service.init(this)) 271 | { 272 | DbgPrint("TCPProxy::init m_service.init() failed"); 273 | break; 274 | } 275 | 276 | if (!m_pool.init(threadCount, this)) 277 | { 278 | DbgPrint("TCPProxy::init m_pool.init() failed"); 279 | break; 280 | } 281 | 282 | sockaddr_in addr; 283 | memset(&addr, 0, sizeof(addr)); 284 | addr.sin_family = AF_INET; 285 | if (bindToLocalhost) 286 | { 287 | addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); 288 | } 289 | addr.sin_port = m_port; 290 | 291 | m_listenSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); 292 | if (m_listenSocket == INVALID_SOCKET) 293 | break; 294 | 295 | if (bind(m_listenSocket, (SOCKADDR*)&addr, sizeof(addr)) != 0) 296 | break; 297 | 298 | if (listen(m_listenSocket, SOMAXCONN) != 0) 299 | break; 300 | 301 | m_service.registerSocket(m_listenSocket); 302 | 303 | if (!startAccept(AF_INET)) 304 | break; 305 | 306 | m_ipv4Available = true; 307 | 308 | DbgPrint("TCPProxy::init IPv4 listen socket initialized"); 309 | 310 | result = true; 311 | break; 312 | } 313 | 314 | if (result) 315 | for (;;) 316 | { 317 | sockaddr_in6 addr; 318 | 319 | memset(&addr, 0, sizeof(addr)); 320 | addr.sin6_family = AF_INET6; 321 | if (bindToLocalhost) 322 | { 323 | addr.sin6_addr.u.Byte[15] = 1; 324 | } 325 | addr.sin6_port = m_port; 326 | 327 | m_listenSocket_IPv6 = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); 328 | if (m_listenSocket_IPv6 == INVALID_SOCKET) 329 | break; 330 | 331 | if (bind(m_listenSocket_IPv6, (SOCKADDR*)&addr, sizeof(addr)) != 0) 332 | break; 333 | 334 | if (listen(m_listenSocket_IPv6, SOMAXCONN) != 0) 335 | break; 336 | 337 | m_service.registerSocket(m_listenSocket_IPv6); 338 | 339 | if (!startAccept(AF_INET6)) 340 | break; 341 | 342 | DbgPrint("TCPProxy::init IPv6 listen socket initialized"); 343 | 344 | m_ipv6Available = true; 345 | 346 | break; 347 | } 348 | 349 | if (!result) 350 | { 351 | free(); 352 | } 353 | 354 | return result; 355 | } 356 | 357 | virtual void free() 358 | { 359 | m_service.free(); 360 | m_pool.free(); 361 | 362 | InitializeListHead(&m_eventList); 363 | 364 | PLIST_ENTRY p; 365 | OV_DATA * pov; 366 | while (!IsListEmpty(&m_ovDataList)) 367 | { 368 | p = RemoveHeadList(&m_ovDataList); 369 | pov = CONTAINING_RECORD(p, OV_DATA, entry); 370 | delete pov; 371 | } 372 | 373 | while (!m_socketMap.empty()) 374 | { 375 | tSocketMap::iterator it = m_socketMap.begin(); 376 | delete it->second; 377 | m_socketMap.erase(it); 378 | } 379 | 380 | if (m_listenSocket != INVALID_SOCKET) 381 | { 382 | closesocket(m_listenSocket); 383 | m_listenSocket = INVALID_SOCKET; 384 | } 385 | if (m_acceptSocket != INVALID_SOCKET) 386 | { 387 | closesocket(m_acceptSocket); 388 | m_acceptSocket = INVALID_SOCKET; 389 | } 390 | if (m_listenSocket_IPv6 != INVALID_SOCKET) 391 | { 392 | closesocket(m_listenSocket_IPv6); 393 | m_listenSocket_IPv6 = INVALID_SOCKET; 394 | } 395 | if (m_acceptSocket_IPv6 != INVALID_SOCKET) 396 | { 397 | closesocket(m_acceptSocket_IPv6); 398 | m_acceptSocket_IPv6 = INVALID_SOCKET; 399 | } 400 | 401 | m_port = 0; 402 | m_pPFEventHandler = NULL; 403 | m_ipv4Available = false; 404 | m_ipv6Available = false; 405 | } 406 | 407 | bool setProxy(NFAPI_NS ENDPOINT_ID id, PROXY_TYPE proxyType, 408 | const char * proxyAddress, int proxyAddressLen, 409 | const char * userName = NULL, const char * userPassword = NULL) 410 | { 411 | DbgPrint("TCPProxy::setProxy[%I64u], type=%d", id, proxyType); 412 | 413 | if (id == 0) 414 | { 415 | if (proxyAddress) 416 | { 417 | memcpy(m_proxyAddress, proxyAddress, 418 | (proxyAddressLen < sizeof(m_proxyAddress))? proxyAddressLen : sizeof(m_proxyAddress)); 419 | m_proxyAddressLen = proxyAddressLen; 420 | m_proxyType = proxyType; 421 | 422 | if (userName) 423 | { 424 | m_userName = userName; 425 | } 426 | if (userPassword) 427 | { 428 | m_userPassword = userPassword; 429 | } 430 | } else 431 | { 432 | m_proxyType = PROXY_NONE; 433 | m_proxyAddressLen = 0; 434 | m_userName = ""; 435 | m_userPassword = ""; 436 | } 437 | 438 | return true; 439 | } 440 | 441 | AutoProxyData pd(this, id); 442 | if (!pd) 443 | return false; 444 | 445 | if (proxyAddress) 446 | { 447 | memcpy(pd->proxyAddress, proxyAddress, 448 | (proxyAddressLen < sizeof(pd->proxyAddress))? proxyAddressLen : sizeof(pd->proxyAddress)); 449 | pd->proxyAddressLen = proxyAddressLen; 450 | pd->proxyType = proxyType; 451 | 452 | if (userName) 453 | { 454 | pd->userName = userName; 455 | } 456 | if (userPassword) 457 | { 458 | pd->userPassword = userPassword; 459 | } 460 | } else 461 | { 462 | pd->proxyType = PROXY_NONE; 463 | pd->proxyAddressLen = 0; 464 | pd->userName = ""; 465 | pd->userPassword = ""; 466 | } 467 | 468 | return true; 469 | } 470 | 471 | void setEventHandler(NFAPI_NS NF_EventHandler * pEventHandler) 472 | { 473 | m_pPFEventHandler = pEventHandler; 474 | } 475 | 476 | void setTimeout(DWORD value) 477 | { 478 | AutoLock lock(m_cs); 479 | 480 | if (value < 5) 481 | value = 5; 482 | 483 | m_timeout = value * 1000; 484 | } 485 | 486 | virtual bool getRemoteAddress(sockaddr * pRemoteAddr, NFAPI_NS PNF_TCP_CONN_INFO pConnInfo) = 0; 487 | 488 | bool tcpPostSend(NFAPI_NS ENDPOINT_ID id, const char * buf, int len) 489 | { 490 | DbgPrint("TCPProxy::tcpPostSend[%I64u], len=%d", id, len); 491 | 492 | AutoProxyData pd(this, id); 493 | if (!pd) 494 | return false; 495 | 496 | if (pd->offline) 497 | { 498 | return true; 499 | } 500 | 501 | return startTcpSend(pd, OUT_SOCKET, buf, len, id); 502 | } 503 | 504 | bool tcpPostReceive(NFAPI_NS ENDPOINT_ID id, const char * buf, int len) 505 | { 506 | DbgPrint("TCPProxy::tcpPostReceive[%I64u], len=%d", id, len); 507 | AutoProxyData pd(this, id); 508 | if (!pd) 509 | return false; 510 | 511 | return startTcpSend(pd, IN_SOCKET, buf, len, id); 512 | } 513 | 514 | bool tcpSetState(NFAPI_NS ENDPOINT_ID id, bool suspended) 515 | { 516 | DbgPrint("TCPProxy::tcpSetState[%I64u], suspended=%d", id, suspended); 517 | 518 | AutoProxyData pd(this, id); 519 | if (!pd) 520 | return false; 521 | 522 | pd->suspended = suspended; 523 | 524 | if (!suspended) 525 | { 526 | if (pd->proxyState == PS_CONNECTED) 527 | { 528 | startTcpReceive(pd, IN_SOCKET, id); 529 | 530 | if (!pd->offline) 531 | { 532 | startTcpReceive(pd, OUT_SOCKET, id); 533 | } 534 | } 535 | } 536 | 537 | return true; 538 | } 539 | 540 | bool tcpClose(NFAPI_NS ENDPOINT_ID id) 541 | { 542 | DbgPrint("TCPProxy::tcpClose[%I64u]", id); 543 | 544 | AutoProxyData pd(this, id); 545 | if (!pd) 546 | return false; 547 | 548 | if (pd->proxyState != PS_CLOSED) 549 | { 550 | pd->proxyState = PS_CLOSED; 551 | releaseProxyData(pd); 552 | } 553 | return true; 554 | } 555 | 556 | bool getTCPConnInfo(NFAPI_NS ENDPOINT_ID id, NFAPI_NS PNF_TCP_CONN_INFO pConnInfo) 557 | { 558 | AutoProxyData pd(this, id); 559 | if (!pd) 560 | return false; 561 | 562 | *pConnInfo = pd->connInfo; 563 | return true; 564 | } 565 | 566 | protected: 567 | 568 | OV_DATA * newOV_DATA() 569 | { 570 | OV_DATA * pov = new OV_DATA(); 571 | AutoLock lock(m_cs); 572 | InsertTailList(&m_ovDataList, &pov->entry); 573 | m_ovDataCounter++; 574 | return pov; 575 | } 576 | 577 | void deleteOV_DATA(OV_DATA * pov) 578 | { 579 | AutoLock lock(m_cs); 580 | RemoveEntryList(&pov->entry); 581 | InitializeListHead(&pov->entry); 582 | delete pov; 583 | m_ovDataCounter--; 584 | DbgPrint("TCPProxy::deleteOV_DATA ov set size=%d", m_ovDataCounter); 585 | } 586 | 587 | class AutoProxyData 588 | { 589 | public: 590 | AutoProxyData(TCPProxy * pThis, NFAPI_NS ENDPOINT_ID id) 591 | { 592 | thisClass = pThis; 593 | ptr = pThis->findProxyData(id); 594 | if (ptr) 595 | { 596 | ptr->lock.Lock(); 597 | } 598 | } 599 | ~AutoProxyData() 600 | { 601 | if (ptr) 602 | { 603 | ptr->lock.Unlock(); 604 | thisClass->releaseProxyData(ptr); 605 | } 606 | } 607 | PROXY_DATA * operator ->() 608 | { 609 | return ptr; 610 | } 611 | operator PROXY_DATA*() 612 | { 613 | return ptr; 614 | } 615 | TCPProxy * thisClass; 616 | PROXY_DATA * ptr; 617 | }; 618 | 619 | PROXY_DATA * findProxyData(NFAPI_NS ENDPOINT_ID id) 620 | { 621 | AutoLock lock(m_cs); 622 | 623 | tSocketMap::iterator it = m_socketMap.find(id); 624 | if (it == m_socketMap.end()) 625 | return NULL; 626 | 627 | if (it->second->proxyState == PS_CLOSED) 628 | return NULL; 629 | 630 | it->second->refCount++; 631 | 632 | return it->second; 633 | } 634 | 635 | int releaseProxyData(PROXY_DATA * pd) 636 | { 637 | AutoLock lock(m_cs); 638 | 639 | if (pd->refCount > 0) 640 | { 641 | pd->refCount--; 642 | } 643 | 644 | if (pd->refCount == 0) 645 | { 646 | DbgPrint("TCPProxy::releaseProxyData[%I64u] delete", pd->id); 647 | 648 | if (m_pPFEventHandler) 649 | { 650 | m_pPFEventHandler->tcpClosed(pd->id, &pd->connInfo); 651 | } 652 | 653 | m_socketMap.erase(pd->id); 654 | delete pd; 655 | 656 | DbgPrint("TCPProxy::releaseProxyData socket map size=%d", m_socketMap.size()); 657 | 658 | return 0; 659 | } 660 | return pd->refCount; 661 | } 662 | 663 | void * getExtensionFunction(SOCKET s, const GUID *which_fn) 664 | { 665 | void *ptr = NULL; 666 | DWORD bytes=0; 667 | WSAIoctl(s, 668 | SIO_GET_EXTENSION_FUNCTION_POINTER, 669 | (GUID*)which_fn, sizeof(*which_fn), 670 | &ptr, sizeof(ptr), 671 | &bytes, 672 | NULL, 673 | NULL); 674 | return ptr; 675 | } 676 | 677 | bool initExtensions() 678 | { 679 | const GUID acceptex = WSAID_ACCEPTEX; 680 | const GUID connectex = WSAID_CONNECTEX; 681 | const GUID getacceptexsockaddrs = WSAID_GETACCEPTEXSOCKADDRS; 682 | 683 | SOCKET s = socket(AF_INET, SOCK_STREAM, 0); 684 | if (s == INVALID_SOCKET) 685 | return false; 686 | 687 | m_pAcceptEx = (LPFN_ACCEPTEX)getExtensionFunction(s, &acceptex); 688 | m_pConnectEx = (LPFN_CONNECTEX)getExtensionFunction(s, &connectex); 689 | m_pGetAcceptExSockaddrs = (LPFN_GETACCEPTEXSOCKADDRS)getExtensionFunction(s, &getacceptexsockaddrs); 690 | 691 | closesocket(s); 692 | 693 | return m_pAcceptEx!= NULL && m_pConnectEx != NULL && m_pGetAcceptExSockaddrs != NULL; 694 | } 695 | 696 | bool startAccept(int ipFamily) 697 | { 698 | SOCKET s = WSASocket(ipFamily, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); 699 | if (s == INVALID_SOCKET) 700 | { 701 | return false; 702 | } 703 | 704 | OV_DATA * pov = newOV_DATA(); 705 | DWORD dwBytes; 706 | 707 | pov->type = OVT_ACCEPT; 708 | pov->packetList.push_back(TCP_PACKET(NULL, 2 * (sizeof(sockaddr_in6) + 16))); 709 | 710 | if (ipFamily == AF_INET) 711 | { 712 | m_acceptSocket = s; 713 | } else 714 | { 715 | m_acceptSocket_IPv6 = s; 716 | } 717 | 718 | if (!m_pAcceptEx((ipFamily == AF_INET)? m_listenSocket : m_listenSocket_IPv6, 719 | s, 720 | pov->packetList[0].buffer.buf, 721 | 0, 722 | sizeof(sockaddr_in6) + 16, 723 | sizeof(sockaddr_in6) + 16, 724 | &dwBytes, 725 | &pov->ol)) 726 | { 727 | if (WSAGetLastError() != ERROR_IO_PENDING) 728 | { 729 | closesocket(s); 730 | deleteOV_DATA(pov); 731 | return false; 732 | } 733 | } 734 | 735 | return true; 736 | } 737 | 738 | 739 | bool startConnect(SOCKET socket, sockaddr * pAddr, int addrLen, NFAPI_NS ENDPOINT_ID id) 740 | { 741 | OV_DATA * pov = newOV_DATA(); 742 | pov->type = OVT_CONNECT; 743 | pov->id = id; 744 | 745 | DbgPrint("TCPProxy::startConnect[%I64u], socket=%d", id, socket); 746 | 747 | if (pAddr->sa_family == AF_INET) 748 | { 749 | struct sockaddr_in addr; 750 | ZeroMemory(&addr, sizeof(addr)); 751 | addr.sin_family = AF_INET; 752 | 753 | bind(socket, (SOCKADDR*) &addr, sizeof(addr)); 754 | } else 755 | { 756 | struct sockaddr_in6 addr; 757 | ZeroMemory(&addr, sizeof(addr)); 758 | addr.sin6_family = AF_INET6; 759 | 760 | bind(socket, (SOCKADDR*) &addr, sizeof(addr)); 761 | } 762 | 763 | if (!m_pConnectEx(socket, pAddr, addrLen, NULL, 0, NULL, &pov->ol)) 764 | { 765 | int err = WSAGetLastError(); 766 | if (err != ERROR_IO_PENDING) 767 | { 768 | DbgPrint("TCPProxy::startConnect[%I64u] failed, err=%d", id, err); 769 | deleteOV_DATA(pov); 770 | return false; 771 | } 772 | } 773 | 774 | return true; 775 | } 776 | 777 | bool startTcpSend(PROXY_DATA * pd, bool isInSocket, const char * buf, int len, NFAPI_NS ENDPOINT_ID id) 778 | { 779 | DbgPrint("TCPProxy::startTcpSend[%I64u] isInSocket=%d, len=%d", id, isInSocket, len); 780 | 781 | SOCKET_DATA * psd; 782 | 783 | if (isInSocket) 784 | { 785 | psd = &pd->inSocket; 786 | } else 787 | { 788 | psd = &pd->outSocket; 789 | } 790 | 791 | if (len == 0) 792 | { 793 | psd->disconnect = true; 794 | } else 795 | if (len != -1) 796 | { 797 | psd->packetList.push_back(TCP_PACKET(buf, len)); 798 | } 799 | 800 | if (psd->sendInProgress) 801 | { 802 | return true; 803 | } 804 | 805 | if (psd->packetList.empty()) 806 | { 807 | if (psd->disconnect) 808 | { 809 | if (isInSocket) 810 | { 811 | startClose(pd->outSocket.socket, id); 812 | } else 813 | { 814 | startClose(pd->inSocket.socket, id); 815 | } 816 | } 817 | return true; 818 | } 819 | 820 | OV_DATA * pov; 821 | DWORD dwBytes; 822 | 823 | pov = newOV_DATA(); 824 | 825 | pov->type = OVT_SEND; 826 | pov->id = id; 827 | pov->packetList = psd->packetList; 828 | 829 | psd->packetList.clear(); 830 | 831 | if (psd->closed || 832 | psd->socket == INVALID_SOCKET) 833 | { 834 | pov->type = OVT_RECEIVE; 835 | if (!m_service.postCompletion(psd->socket, 0, &pov->ol)) 836 | { 837 | deleteOV_DATA(pov); 838 | } 839 | return false; 840 | } 841 | 842 | psd->sendInProgress = true; 843 | 844 | if (WSASend(psd->socket, 845 | &pov->packetList[0](), (DWORD)pov->packetList.size(), 846 | &dwBytes, 0, &pov->ol, NULL) != 0) 847 | { 848 | int err = WSAGetLastError(); 849 | if (err != ERROR_IO_PENDING) 850 | { 851 | DbgPrint("TCPProxy::startTcpSend[%I64u] failed, err=%d", id, err); 852 | 853 | psd->closed = true; 854 | psd->sendInProgress = false; 855 | 856 | pov->type = OVT_RECEIVE; 857 | if (!m_service.postCompletion(psd->socket, 0, &pov->ol)) 858 | { 859 | deleteOV_DATA(pov); 860 | } 861 | 862 | return false; 863 | } 864 | } 865 | 866 | return true; 867 | } 868 | 869 | bool startTcpReceive(PROXY_DATA * pd, bool isInSocket, NFAPI_NS ENDPOINT_ID id) 870 | { 871 | DbgPrint("TCPProxy::startTcpReceive[%I64u] isInSocket=%d", id, isInSocket); 872 | 873 | SOCKET_DATA * psd; 874 | 875 | if (isInSocket) 876 | { 877 | psd = &pd->inSocket; 878 | } else 879 | { 880 | psd = &pd->outSocket; 881 | } 882 | 883 | if (psd->closed || 884 | psd->disconnected || 885 | psd->socket == INVALID_SOCKET) 886 | { 887 | return false; 888 | } 889 | 890 | if (psd->receiveInProgress) 891 | { 892 | return true; 893 | } 894 | 895 | if (pd->suspended && 896 | pd->proxyState == PS_CONNECTED && 897 | !psd->disconnect) 898 | { 899 | return true; 900 | } 901 | 902 | OV_DATA * pov; 903 | DWORD dwBytes, dwFlags; 904 | 905 | pov = newOV_DATA(); 906 | pov->type = OVT_RECEIVE; 907 | pov->id = id; 908 | pov->packetList.push_back(TCP_PACKET(NULL, TCP_PACKET_SIZE)); 909 | 910 | dwFlags = 0; 911 | 912 | psd->receiveInProgress = true; 913 | 914 | if (WSARecv(psd->socket, &pov->packetList[0](), 1, &dwBytes, &dwFlags, &pov->ol, NULL) != 0) 915 | { 916 | int err = WSAGetLastError(); 917 | if (err != ERROR_IO_PENDING) 918 | { 919 | DbgPrint("TCPProxy::startTcpReceive[%I64u] failed, err=%d", id, err); 920 | 921 | psd->closed = true; 922 | psd->receiveInProgress = false; 923 | 924 | if (!m_service.postCompletion(psd->socket, 0, &pov->ol)) 925 | { 926 | deleteOV_DATA(pov); 927 | } 928 | 929 | return false; 930 | } 931 | } 932 | 933 | return true; 934 | } 935 | 936 | bool startClose(SOCKET socket, NFAPI_NS ENDPOINT_ID id) 937 | { 938 | DbgPrint("TCPProxy::startClose[%I64u] socket %d", 939 | id, 940 | socket); 941 | 942 | OV_DATA * pov = newOV_DATA(); 943 | pov->type = OVT_CLOSE; 944 | pov->id = id; 945 | return m_service.postCompletion(socket, 0, &pov->ol); 946 | } 947 | 948 | void onConnectComplete(SOCKET socket, DWORD dwTransferred, OV_DATA * pov, int error) 949 | { 950 | if (error != 0) 951 | { 952 | DbgPrint("TCPProxy::onConnectComplete[%I64u] failed, err=%d", pov->id, error); 953 | startClose(socket, pov->id); 954 | return; 955 | } 956 | 957 | DbgPrint("TCPProxy::onConnectComplete[%I64u] err=%d", pov->id, error); 958 | 959 | AutoProxyData pd(this, pov->id); 960 | if (!pd) 961 | return; 962 | 963 | BOOL val = 1; 964 | setsockopt(socket, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0); 965 | setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char*)&val, sizeof(val)); 966 | setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, (char*)&val, sizeof(val)); 967 | 968 | setKeepAliveVals(socket); 969 | 970 | if (pd->proxyType == PROXY_SOCKS5) 971 | { 972 | SOCKS5_AUTH_REQUEST authReq; 973 | 974 | authReq.version = SOCKS_5; 975 | authReq.nmethods = 1; 976 | 977 | if (!pd->userName.empty()) 978 | { 979 | authReq.methods[0] = S5AM_UNPW; 980 | } else 981 | { 982 | authReq.methods[0] = S5AM_NONE; 983 | } 984 | 985 | if (startTcpSend(pd, OUT_SOCKET, (char*)&authReq, sizeof(authReq), pov->id)) 986 | { 987 | pd->proxyState = PS_AUTH; 988 | } 989 | 990 | startTcpReceive(pd, OUT_SOCKET, pov->id); 991 | } else 992 | { 993 | pd->proxyState = PS_CONNECTED; 994 | 995 | startTcpReceive(pd, IN_SOCKET, pov->id); 996 | startTcpReceive(pd, OUT_SOCKET, pov->id); 997 | 998 | if (m_pPFEventHandler) 999 | { 1000 | m_pPFEventHandler->tcpConnected(pov->id, &pd->connInfo); 1001 | } 1002 | } 1003 | } 1004 | 1005 | void onSendComplete(SOCKET socket, DWORD dwTransferred, OV_DATA * pov, int error) 1006 | { 1007 | DbgPrint("TCPProxy::onSendComplete[%I64u] socket=%d, bytes=%d", pov->id, socket, dwTransferred); 1008 | 1009 | AutoProxyData pd(this, pov->id); 1010 | if (!pd) 1011 | return; 1012 | 1013 | SOCKET_DATA * psd; 1014 | bool isInSocket; 1015 | 1016 | if (pd->inSocket.socket == socket) 1017 | { 1018 | isInSocket = true; 1019 | psd = &pd->inSocket; 1020 | } else 1021 | { 1022 | isInSocket = false; 1023 | psd = &pd->outSocket; 1024 | } 1025 | 1026 | psd->sendInProgress = false; 1027 | 1028 | if (dwTransferred == 0) 1029 | { 1030 | DbgPrint("TCPProxy::onSendComplete[%I64u] error=%d", pov->id, error); 1031 | 1032 | psd->closed = true; 1033 | 1034 | OV_DATA * newpov = newOV_DATA(); 1035 | newpov->id = pov->id; 1036 | newpov->type = OVT_RECEIVE; 1037 | if (!m_service.postCompletion(socket, 0, &newpov->ol)) 1038 | { 1039 | deleteOV_DATA(newpov); 1040 | } 1041 | return; 1042 | } 1043 | 1044 | if (psd->disconnect || !psd->packetList.empty()) 1045 | { 1046 | startTcpSend(pd, isInSocket, NULL, -1, pov->id); 1047 | } else 1048 | if (pd->proxyState == PS_CONNECTED) 1049 | { 1050 | if (m_pPFEventHandler) 1051 | { 1052 | if (isInSocket) 1053 | { 1054 | m_pPFEventHandler->tcpCanReceive(pov->id); 1055 | } else 1056 | { 1057 | m_pPFEventHandler->tcpCanSend(pov->id); 1058 | } 1059 | } 1060 | 1061 | if (!pd->offline) 1062 | { 1063 | startTcpReceive(pd, !isInSocket, pov->id); 1064 | } 1065 | } 1066 | } 1067 | 1068 | void onReceiveComplete(SOCKET socket, DWORD dwTransferred, OV_DATA * pov, int error) 1069 | { 1070 | DbgPrint("TCPProxy::onReceiveComplete[%I64u] socket=%d, bytes=%d", pov->id, socket, dwTransferred); 1071 | 1072 | AutoProxyData pd(this, pov->id); 1073 | if (!pd) 1074 | return; 1075 | 1076 | SOCKET_DATA * psd; 1077 | bool isInSocket; 1078 | 1079 | if (pd->inSocket.socket == socket) 1080 | { 1081 | isInSocket = true; 1082 | psd = &pd->inSocket; 1083 | } else 1084 | { 1085 | isInSocket = false; 1086 | psd = &pd->outSocket; 1087 | } 1088 | 1089 | psd->receiveInProgress = false; 1090 | 1091 | if (dwTransferred == 0) 1092 | { 1093 | if (error != 0) 1094 | { 1095 | DbgPrint("TCPProxy::onReceiveComplete[%I64u] error=%d", pov->id, error); 1096 | psd->closed = true; 1097 | } 1098 | 1099 | if (pd->proxyState == PS_CONNECTED && 1100 | m_pPFEventHandler && 1101 | pd->connInfo.filteringFlag & NFAPI_NS NF_FILTER) 1102 | { 1103 | if (pd->outSocket.socket == socket) 1104 | { 1105 | pd->outSocket.disconnected = true; 1106 | m_pPFEventHandler->tcpReceive(pov->id, NULL, 0); 1107 | } else 1108 | { 1109 | pd->inSocket.disconnected = true; 1110 | if (pd->offline) 1111 | { 1112 | m_pPFEventHandler->tcpReceive(pov->id, NULL, 0); 1113 | } 1114 | m_pPFEventHandler->tcpSend(pov->id, NULL, 0); 1115 | } 1116 | } else 1117 | { 1118 | startClose(socket, pov->id); 1119 | } 1120 | 1121 | return; 1122 | } 1123 | 1124 | if (isInSocket == OUT_SOCKET) 1125 | { 1126 | if (pd->proxyState == PS_CONNECTED) 1127 | { 1128 | if (m_pPFEventHandler && 1129 | pd->connInfo.filteringFlag & NFAPI_NS NF_FILTER) 1130 | { 1131 | m_pPFEventHandler->tcpReceive(pov->id, pov->packetList[0].buffer.buf, dwTransferred); 1132 | 1133 | startTcpReceive(pd, OUT_SOCKET, pov->id); 1134 | } else 1135 | { 1136 | if (!startTcpSend(pd, IN_SOCKET, pov->packetList[0].buffer.buf, dwTransferred, pov->id)) 1137 | { 1138 | DbgPrint("TCPProxy::onReceiveComplete startTcpSend failed"); 1139 | } 1140 | } 1141 | } else 1142 | { 1143 | switch (pd->proxyState) 1144 | { 1145 | case PS_NONE: 1146 | break; 1147 | 1148 | case PS_AUTH: 1149 | { 1150 | if (dwTransferred < sizeof(SOCK5_AUTH_RESPONSE)) 1151 | break; 1152 | 1153 | SOCK5_AUTH_RESPONSE * pr = (SOCK5_AUTH_RESPONSE *)pov->packetList[0].buffer.buf; 1154 | 1155 | if (pr->version != SOCKS_5) 1156 | { 1157 | break; 1158 | } 1159 | 1160 | if (pr->method == S5AM_UNPW && !pd->userName.empty()) 1161 | { 1162 | std::vector authReq; 1163 | 1164 | authReq.push_back(1); 1165 | authReq.push_back((char)pd->userName.length()); 1166 | authReq.insert(authReq.end(), pd->userName.begin(), pd->userName.end()); 1167 | authReq.push_back((char)pd->userPassword.length()); 1168 | 1169 | if (!pd->userPassword.empty()) 1170 | authReq.insert(authReq.end(), pd->userPassword.begin(), pd->userPassword.end()); 1171 | 1172 | if (startTcpSend(pd, OUT_SOCKET, (char*)&authReq[0], (int)authReq.size(), pov->id)) 1173 | { 1174 | pd->proxyState = PS_AUTH_NEGOTIATION; 1175 | } 1176 | 1177 | break; 1178 | } 1179 | 1180 | char * realRemoteAddress = (char*)pd->connInfo.remoteAddress; 1181 | int realRemoteAddressLen = (((sockaddr*)realRemoteAddress)->sa_family == AF_INET)? sizeof(sockaddr_in) : sizeof(sockaddr_in6); 1182 | 1183 | int ipFamily = ((sockaddr*)realRemoteAddress)->sa_family; 1184 | 1185 | if (ipFamily == AF_INET) 1186 | { 1187 | SOCKS5_REQUEST_IPv4 req; 1188 | 1189 | req.version = SOCKS_5; 1190 | req.command = S5C_CONNECT; 1191 | req.reserved = 0; 1192 | req.address_type = SOCKS5_ADDR_IPV4; 1193 | req.address = ((sockaddr_in*)realRemoteAddress)->sin_addr.S_un.S_addr; 1194 | req.port = ((sockaddr_in*)realRemoteAddress)->sin_port; 1195 | 1196 | if (startTcpSend(pd, OUT_SOCKET, (char*)&req, sizeof(req), pov->id)) 1197 | { 1198 | pd->proxyState = PS_CONNECT; 1199 | } 1200 | } else 1201 | { 1202 | SOCKS5_REQUEST_IPv6 req; 1203 | 1204 | req.version = SOCKS_5; 1205 | req.command = S5C_CONNECT; 1206 | req.reserved = 0; 1207 | req.address_type = SOCKS5_ADDR_IPV6; 1208 | memcpy(&req.address, &((sockaddr_in6*)realRemoteAddress)->sin6_addr, 16); 1209 | req.port = ((sockaddr_in6*)realRemoteAddress)->sin6_port; 1210 | 1211 | if (startTcpSend(pd, OUT_SOCKET, (char*)&req, sizeof(req), pov->id)) 1212 | { 1213 | pd->proxyState = PS_CONNECT; 1214 | } 1215 | } 1216 | } 1217 | break; 1218 | 1219 | case PS_AUTH_NEGOTIATION: 1220 | { 1221 | if (dwTransferred < sizeof(SOCK5_AUTH_RESPONSE)) 1222 | break; 1223 | 1224 | SOCK5_AUTH_RESPONSE * pr = (SOCK5_AUTH_RESPONSE *)pov->packetList[0].buffer.buf; 1225 | 1226 | if (pr->version != 0x01 || pr->method != 0x00) 1227 | { 1228 | break; 1229 | } 1230 | 1231 | char * realRemoteAddress = (char*)pd->connInfo.remoteAddress; 1232 | int realRemoteAddressLen = (((sockaddr*)realRemoteAddress)->sa_family == AF_INET)? sizeof(sockaddr_in) : sizeof(sockaddr_in6); 1233 | 1234 | int ipFamily = ((sockaddr*)realRemoteAddress)->sa_family; 1235 | 1236 | if (ipFamily == AF_INET) 1237 | { 1238 | SOCKS5_REQUEST_IPv4 req; 1239 | 1240 | req.version = SOCKS_5; 1241 | req.command = S5C_CONNECT; 1242 | req.reserved = 0; 1243 | req.address_type = SOCKS5_ADDR_IPV4; 1244 | req.address = ((sockaddr_in*)realRemoteAddress)->sin_addr.S_un.S_addr; 1245 | req.port = ((sockaddr_in*)realRemoteAddress)->sin_port; 1246 | 1247 | if (startTcpSend(pd, OUT_SOCKET, (char*)&req, sizeof(req), pov->id)) 1248 | { 1249 | pd->proxyState = PS_CONNECT; 1250 | } 1251 | } else 1252 | { 1253 | SOCKS5_REQUEST_IPv6 req; 1254 | 1255 | req.version = SOCKS_5; 1256 | req.command = S5C_CONNECT; 1257 | req.reserved = 0; 1258 | req.address_type = SOCKS5_ADDR_IPV6; 1259 | memcpy(&req.address, &((sockaddr_in6*)realRemoteAddress)->sin6_addr, 16); 1260 | req.port = ((sockaddr_in6*)realRemoteAddress)->sin6_port; 1261 | 1262 | if (startTcpSend(pd, OUT_SOCKET, (char*)&req, sizeof(req), pov->id)) 1263 | { 1264 | pd->proxyState = PS_CONNECT; 1265 | } 1266 | } 1267 | } 1268 | break; 1269 | 1270 | case PS_CONNECT: 1271 | { 1272 | if (dwTransferred < sizeof(SOCKS5_RESPONSE)) 1273 | break; 1274 | 1275 | SOCKS5_RESPONSE * pr = (SOCKS5_RESPONSE *)pov->packetList[0].buffer.buf; 1276 | 1277 | if (pr->version != SOCKS_5 || pr->res_code != 0) 1278 | break; 1279 | 1280 | DWORD responseLen = (pr->address_type == SOCKS5_ADDR_IPV4)? 1281 | sizeof(SOCKS5_RESPONSE_IPv4) : sizeof(SOCKS5_RESPONSE_IPv6); 1282 | 1283 | pd->proxyState = PS_CONNECTED; 1284 | 1285 | if (m_pPFEventHandler) 1286 | { 1287 | m_pPFEventHandler->tcpConnected(pov->id, &pd->connInfo); 1288 | } 1289 | 1290 | if (dwTransferred > responseLen) 1291 | { 1292 | if (m_pPFEventHandler && 1293 | pd->connInfo.filteringFlag & NFAPI_NS NF_FILTER) 1294 | { 1295 | m_pPFEventHandler->tcpReceive(pov->id, 1296 | pov->packetList[0].buffer.buf + responseLen, 1297 | dwTransferred - responseLen); 1298 | } else 1299 | { 1300 | if (!startTcpSend(pd, IN_SOCKET, 1301 | pov->packetList[0].buffer.buf + responseLen, 1302 | dwTransferred - responseLen, pov->id)) 1303 | { 1304 | DbgPrint("TCPProxy::onReceiveComplete startTcpSend failed"); 1305 | } 1306 | } 1307 | } 1308 | 1309 | startTcpReceive(pd, IN_SOCKET, pov->id); 1310 | startTcpReceive(pd, OUT_SOCKET, pov->id); 1311 | } 1312 | break; 1313 | } 1314 | 1315 | startTcpReceive(pd, OUT_SOCKET, pov->id); 1316 | } 1317 | 1318 | } else 1319 | // IN_SOCKET 1320 | { 1321 | if (pd->proxyState == PS_CONNECTED) 1322 | { 1323 | if (m_pPFEventHandler && 1324 | pd->connInfo.filteringFlag & NFAPI_NS NF_FILTER) 1325 | { 1326 | m_pPFEventHandler->tcpSend(pov->id, pov->packetList[0].buffer.buf, dwTransferred); 1327 | 1328 | startTcpReceive(pd, IN_SOCKET, pov->id); 1329 | } else 1330 | { 1331 | if (!startTcpSend(pd, OUT_SOCKET, pov->packetList[0].buffer.buf, dwTransferred, pov->id)) 1332 | { 1333 | DbgPrint("TCPProxy::onReceiveComplete startTcpSend failed"); 1334 | } 1335 | } 1336 | } else 1337 | { 1338 | startClose(socket, pov->id); 1339 | } 1340 | } 1341 | } 1342 | 1343 | void setKeepAliveVals(SOCKET s) 1344 | { 1345 | tcp_keepalive tk; 1346 | DWORD dwRet; 1347 | 1348 | { 1349 | AutoLock lock(m_cs); 1350 | 1351 | tk.onoff = 1; 1352 | tk.keepalivetime = m_timeout; 1353 | tk.keepaliveinterval = 1000; 1354 | } 1355 | 1356 | int err = WSAIoctl(s, SIO_KEEPALIVE_VALS, 1357 | (LPVOID) &tk, 1358 | (DWORD) sizeof(tk), 1359 | NULL, 1360 | 0, 1361 | (LPDWORD) &dwRet, 1362 | NULL, 1363 | NULL); 1364 | if (err != 0) 1365 | { 1366 | DbgPrint("TCPProxy::setKeepAliveVals WSAIoctl err=%d", WSAGetLastError()); 1367 | } 1368 | } 1369 | 1370 | void onAcceptComplete(SOCKET socket, DWORD dwTransferred, OV_DATA * pov, int error) 1371 | { 1372 | sockaddr * pLocalAddr = NULL; 1373 | sockaddr * pRemoteAddr = NULL; 1374 | int localAddrLen, remoteAddrLen; 1375 | char realRemoteAddress[NF_MAX_ADDRESS_LENGTH]; 1376 | SOCKET acceptSocket; 1377 | int ipFamily; 1378 | bool result = false; 1379 | 1380 | if (socket == m_listenSocket) 1381 | { 1382 | acceptSocket = m_acceptSocket; 1383 | ipFamily = AF_INET; 1384 | } else 1385 | { 1386 | acceptSocket = m_acceptSocket_IPv6; 1387 | ipFamily = AF_INET6; 1388 | } 1389 | 1390 | if (error != 0) 1391 | { 1392 | DbgPrint("TCPProxy::onAcceptComplete() failed, err=%d", error); 1393 | 1394 | closesocket(acceptSocket); 1395 | 1396 | if (!startAccept(ipFamily)) 1397 | { 1398 | DbgPrint("TCPProxy::startAccept() failed"); 1399 | } 1400 | return; 1401 | } 1402 | 1403 | m_pGetAcceptExSockaddrs(pov->packetList[0].buffer.buf, 1404 | 0, 1405 | sizeof(sockaddr_in6) + 16, 1406 | sizeof(sockaddr_in6) + 16, 1407 | &pLocalAddr, 1408 | &localAddrLen, 1409 | &pRemoteAddr, 1410 | &remoteAddrLen); 1411 | 1412 | { 1413 | #if defined(_DEBUG) || defined(_RELEASE_LOG) 1414 | char localAddr[MAX_PATH] = ""; 1415 | char remoteAddr[MAX_PATH] = ""; 1416 | DWORD dwLen; 1417 | sockaddr * pAddr; 1418 | 1419 | pAddr = pLocalAddr; 1420 | dwLen = sizeof(localAddr); 1421 | 1422 | WSAAddressToString((LPSOCKADDR)pAddr, 1423 | (pAddr->sa_family == AF_INET6)? sizeof(sockaddr_in6) : sizeof(sockaddr_in), 1424 | NULL, 1425 | localAddr, 1426 | &dwLen); 1427 | 1428 | pAddr = pRemoteAddr; 1429 | dwLen = sizeof(remoteAddr); 1430 | 1431 | WSAAddressToString((LPSOCKADDR)pAddr, 1432 | (pAddr->sa_family == AF_INET6)? sizeof(sockaddr_in6) : sizeof(sockaddr_in), 1433 | NULL, 1434 | remoteAddr, 1435 | &dwLen); 1436 | 1437 | DbgPrint("TCPProxy::onAcceptComplete() accepted socket %d, %s <- %s", 1438 | acceptSocket, 1439 | localAddr, 1440 | remoteAddr); 1441 | #endif 1442 | } 1443 | 1444 | m_service.registerSocket(acceptSocket); 1445 | 1446 | setsockopt(acceptSocket, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char*)&m_listenSocket, sizeof(m_listenSocket)); 1447 | 1448 | BOOL val = 1; 1449 | setsockopt(acceptSocket, IPPROTO_TCP, TCP_NODELAY, (char*)&val, sizeof(val)); 1450 | setsockopt(acceptSocket, SOL_SOCKET, SO_KEEPALIVE, (char*)&val, sizeof(val)); 1451 | 1452 | setKeepAliveVals(acceptSocket); 1453 | 1454 | { 1455 | AutoLock lock(m_cs); 1456 | 1457 | PROXY_DATA * pd = new PROXY_DATA(); 1458 | 1459 | pd->inSocket.socket = acceptSocket; 1460 | 1461 | unsigned short remotePort; 1462 | if (((sockaddr*)pLocalAddr)->sa_family == AF_INET) 1463 | { 1464 | remotePort = ((sockaddr_in*)pRemoteAddr)->sin_port; 1465 | } else 1466 | { 1467 | remotePort = ((sockaddr_in6*)pRemoteAddr)->sin6_port; 1468 | } 1469 | 1470 | m_connId++; 1471 | 1472 | pd->id = m_connId; 1473 | 1474 | m_socketMap[pd->id] = pd; 1475 | 1476 | pd->connInfo.ip_family = ((sockaddr*)pLocalAddr)->sa_family; 1477 | pd->connInfo.direction = NFAPI_NS NF_D_OUT; 1478 | memcpy(pd->connInfo.localAddress, pRemoteAddr, remoteAddrLen); 1479 | 1480 | bool addressFound = false; 1481 | 1482 | if (getRemoteAddress(pRemoteAddr, &pd->connInfo)) 1483 | { 1484 | addressFound = true; 1485 | 1486 | if (m_pPFEventHandler) 1487 | { 1488 | pd->connInfo.filteringFlag |= NFAPI_NS NF_FILTER; 1489 | 1490 | m_pPFEventHandler->tcpConnectRequest(pd->id, &pd->connInfo); 1491 | 1492 | if (pd->connInfo.filteringFlag & NFAPI_NS NF_BLOCK) 1493 | { 1494 | addressFound = false; 1495 | } else 1496 | if (pd->connInfo.filteringFlag & NFAPI_NS NF_OFFLINE) 1497 | { 1498 | pd->offline = true; 1499 | result = true; 1500 | } 1501 | } 1502 | 1503 | if (m_proxyType != PROXY_NONE) 1504 | { 1505 | pd->proxyType = m_proxyType; 1506 | memcpy(pd->proxyAddress, m_proxyAddress, sizeof(m_proxyAddress)); 1507 | pd->proxyAddressLen = m_proxyAddressLen; 1508 | pd->userName = m_userName; 1509 | pd->userPassword = m_userPassword; 1510 | } 1511 | 1512 | if (pd->proxyType == PROXY_SOCKS5) 1513 | { 1514 | #if defined(_DEBUG) || defined(_RELEASE_LOG) 1515 | char remoteAddr[MAX_PATH] = ""; 1516 | DWORD dwLen; 1517 | sockaddr * pAddr; 1518 | 1519 | pAddr = (sockaddr*)pd->proxyAddress; 1520 | dwLen = sizeof(remoteAddr); 1521 | 1522 | WSAAddressToString((LPSOCKADDR)pAddr, 1523 | (pAddr->sa_family == AF_INET6)? sizeof(sockaddr_in6) : sizeof(sockaddr_in), 1524 | NULL, 1525 | remoteAddr, 1526 | &dwLen); 1527 | 1528 | DbgPrint("TCPProxy::onAcceptComplete() redirect to SOCKS proxy %s", remoteAddr); 1529 | #endif 1530 | 1531 | memcpy(realRemoteAddress, pd->proxyAddress, sizeof(realRemoteAddress)); 1532 | } else 1533 | { 1534 | memcpy(realRemoteAddress, pd->connInfo.remoteAddress, sizeof(realRemoteAddress)); 1535 | } 1536 | } else 1537 | { 1538 | DbgPrint("TCPProxy::onAcceptComplete real remote address not found"); 1539 | } 1540 | 1541 | if (addressFound) 1542 | { 1543 | if (pd->offline) 1544 | { 1545 | pd->proxyState = PS_CONNECTED; 1546 | pd->outSocket.disconnected = true; 1547 | 1548 | startTcpReceive(pd, IN_SOCKET, pd->id); 1549 | 1550 | if (m_pPFEventHandler) 1551 | { 1552 | m_pPFEventHandler->tcpConnected(pd->id, &pd->connInfo); 1553 | } 1554 | } else 1555 | { 1556 | 1557 | for (;;) 1558 | { 1559 | SOCKET tcpSocket = WSASocket(((sockaddr*)realRemoteAddress)->sa_family, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); 1560 | if (tcpSocket == INVALID_SOCKET) 1561 | { 1562 | DbgPrint("TCPProxy::onAcceptComplete WSASocket failed"); 1563 | break; 1564 | } 1565 | 1566 | pd->outSocket.socket = tcpSocket; 1567 | 1568 | if (!m_service.registerSocket(tcpSocket)) 1569 | { 1570 | DbgPrint("TCPProxy::onAcceptComplete registerSocket failed"); 1571 | break; 1572 | } 1573 | 1574 | if (!startConnect(tcpSocket, 1575 | (sockaddr*)realRemoteAddress, 1576 | (((sockaddr*)realRemoteAddress)->sa_family == AF_INET6)? sizeof(sockaddr_in6) : sizeof(sockaddr_in), 1577 | pd->id)) 1578 | { 1579 | DbgPrint("TCPProxy::onAcceptComplete startConnect failed"); 1580 | break; 1581 | } 1582 | 1583 | result = true; 1584 | 1585 | break; 1586 | } 1587 | } 1588 | } 1589 | 1590 | if (!result) 1591 | { 1592 | m_socketMap.erase(pd->id); 1593 | delete pd; 1594 | } 1595 | } 1596 | 1597 | if (!startAccept(ipFamily)) 1598 | { 1599 | DbgPrint("TCPProxy::startAccept() failed"); 1600 | } 1601 | } 1602 | 1603 | void onClose(SOCKET socket, OV_DATA * pov) 1604 | { 1605 | bool close = false; 1606 | 1607 | DbgPrint("TCPProxy::onClose[%I64u] socket=%d", pov->id, socket); 1608 | 1609 | AutoProxyData pd(this, pov->id); 1610 | if (!pd) 1611 | return; 1612 | 1613 | SOCKET_DATA *psd, *psd2; 1614 | bool isInSocket2; 1615 | 1616 | if (pd->inSocket.socket == socket) 1617 | { 1618 | psd = &pd->inSocket; 1619 | psd2 = &pd->outSocket; 1620 | isInSocket2 = false; 1621 | } else 1622 | { 1623 | psd = &pd->outSocket; 1624 | psd2 = &pd->inSocket; 1625 | isInSocket2 = true; 1626 | } 1627 | 1628 | psd->disconnected = true; 1629 | 1630 | if (!psd2->disconnected && 1631 | !psd2->closed && 1632 | psd2->socket != INVALID_SOCKET) 1633 | { 1634 | if (shutdown(psd2->socket, (psd->closed)? SD_BOTH : SD_SEND) == 0) 1635 | { 1636 | startTcpReceive(pd, isInSocket2, pov->id); 1637 | } else 1638 | { 1639 | DbgPrint("TCPProxy::onClose[%I64u] shutdown error=%d, closed", pov->id, WSAGetLastError()); 1640 | close = true; 1641 | } 1642 | } else 1643 | { 1644 | close = true; 1645 | } 1646 | 1647 | if (close) 1648 | { 1649 | DbgPrint("TCPProxy::onClose[%I64u] closed", pov->id); 1650 | 1651 | if (pd->proxyState != PS_CLOSED) 1652 | { 1653 | pd->proxyState = PS_CLOSED; 1654 | releaseProxyData(pd); 1655 | } 1656 | } 1657 | } 1658 | 1659 | virtual void onComplete(SOCKET socket, DWORD dwTransferred, OVERLAPPED * pOverlapped, int error) 1660 | { 1661 | OV_DATA * pov = (OV_DATA*)pOverlapped; 1662 | 1663 | pov->socket = socket; 1664 | pov->dwTransferred = dwTransferred; 1665 | pov->error = error; 1666 | 1667 | { 1668 | AutoLock lock(m_csEventList); 1669 | InsertTailList(&m_eventList, &pov->entryEventList); 1670 | } 1671 | 1672 | m_pool.jobAvailable(); 1673 | } 1674 | 1675 | virtual void execute() 1676 | { 1677 | OV_DATA * pov; 1678 | 1679 | { 1680 | AutoLock lock(m_csEventList); 1681 | 1682 | if (IsListEmpty(&m_eventList)) 1683 | return; 1684 | 1685 | pov = CONTAINING_RECORD(m_eventList.Flink, OV_DATA, entryEventList); 1686 | 1687 | RemoveEntryList(&pov->entryEventList); 1688 | InitializeListHead(&pov->entryEventList); 1689 | } 1690 | 1691 | if (pov) 1692 | { 1693 | switch (pov->type) 1694 | { 1695 | case OVT_ACCEPT: 1696 | onAcceptComplete(pov->socket, pov->dwTransferred, pov, pov->error); 1697 | break; 1698 | case OVT_CONNECT: 1699 | onConnectComplete(pov->socket, pov->dwTransferred, pov, pov->error); 1700 | break; 1701 | case OVT_SEND: 1702 | onSendComplete(pov->socket, pov->dwTransferred, pov, pov->error); 1703 | break; 1704 | case OVT_RECEIVE: 1705 | onReceiveComplete(pov->socket, pov->dwTransferred, pov, pov->error); 1706 | break; 1707 | case OVT_CLOSE: 1708 | onClose(pov->socket, pov); 1709 | break; 1710 | } 1711 | 1712 | deleteOV_DATA(pov); 1713 | } 1714 | 1715 | { 1716 | AutoLock lock(m_csEventList); 1717 | if (!IsListEmpty(&m_eventList)) 1718 | { 1719 | m_pool.jobAvailable(); 1720 | } 1721 | } 1722 | } 1723 | 1724 | virtual void threadStarted() 1725 | { 1726 | if (m_pPFEventHandler) 1727 | { 1728 | m_pPFEventHandler->threadStart(); 1729 | } 1730 | } 1731 | 1732 | virtual void threadStopped() 1733 | { 1734 | if (m_pPFEventHandler) 1735 | { 1736 | m_pPFEventHandler->threadEnd(); 1737 | } 1738 | } 1739 | 1740 | private: 1741 | IOCPService m_service; 1742 | 1743 | LIST_ENTRY m_ovDataList; 1744 | int m_ovDataCounter; 1745 | 1746 | typedef std::map tSocketMap; 1747 | tSocketMap m_socketMap; 1748 | 1749 | LPFN_ACCEPTEX m_pAcceptEx; 1750 | LPFN_CONNECTEX m_pConnectEx; 1751 | LPFN_GETACCEPTEXSOCKADDRS m_pGetAcceptExSockaddrs; 1752 | 1753 | SOCKET m_listenSocket; 1754 | SOCKET m_acceptSocket; 1755 | 1756 | SOCKET m_listenSocket_IPv6; 1757 | SOCKET m_acceptSocket_IPv6; 1758 | 1759 | NFAPI_NS ENDPOINT_ID m_connId; 1760 | 1761 | unsigned short m_port; 1762 | 1763 | bool m_ipv4Available; 1764 | bool m_ipv6Available; 1765 | 1766 | NFAPI_NS NF_EventHandler * m_pPFEventHandler; 1767 | 1768 | LIST_ENTRY m_eventList; 1769 | AutoCriticalSection m_csEventList; 1770 | 1771 | ThreadPool m_pool; 1772 | 1773 | DWORD m_timeout; 1774 | 1775 | PROXY_TYPE m_proxyType; 1776 | char m_proxyAddress[NF_MAX_ADDRESS_LENGTH]; 1777 | int m_proxyAddressLen; 1778 | 1779 | std::string m_userName; 1780 | std::string m_userPassword; 1781 | 1782 | AutoCriticalSection m_cs; 1783 | }; 1784 | 1785 | class LocalTCPProxy : public TCPProxy 1786 | { 1787 | public: 1788 | void free() 1789 | { 1790 | TCPProxy::free(); 1791 | 1792 | AutoLock lock(m_cs); 1793 | m_connInfoMap.clear(); 1794 | } 1795 | 1796 | void setConnInfo(NFAPI_NS PNF_TCP_CONN_INFO pConnInfo) 1797 | { 1798 | AutoLock lock(m_cs); 1799 | m_connInfoMap[((sockaddr_in*)pConnInfo->localAddress)->sin_port] = *pConnInfo; 1800 | } 1801 | 1802 | virtual bool getRemoteAddress(sockaddr * pRemoteAddr, NFAPI_NS PNF_TCP_CONN_INFO pConnInfo) 1803 | { 1804 | AutoLock lock(m_cs); 1805 | 1806 | unsigned short remotePort = 0; 1807 | 1808 | if (pRemoteAddr->sa_family == AF_INET) 1809 | { 1810 | remotePort = ((sockaddr_in*)pRemoteAddr)->sin_port; 1811 | } else 1812 | { 1813 | remotePort = ((sockaddr_in6*)pRemoteAddr)->sin6_port; 1814 | } 1815 | 1816 | tConnInfoMap::iterator it = m_connInfoMap.find(remotePort); 1817 | if (it != m_connInfoMap.end()) 1818 | { 1819 | *pConnInfo = it->second; 1820 | m_connInfoMap.erase(it); 1821 | return true; 1822 | } 1823 | return false; 1824 | } 1825 | 1826 | private: 1827 | typedef std::map tConnInfoMap; 1828 | tConnInfoMap m_connInfoMap; 1829 | 1830 | AutoCriticalSection m_cs; 1831 | }; 1832 | 1833 | 1834 | } -------------------------------------------------------------------------------- /src/threadpool.h: -------------------------------------------------------------------------------- 1 | // 2 | // NetFilterSDK 3 | // Copyright (C) Vitaly Sidorov 4 | // All rights reserved. 5 | // 6 | // This file is a part of the NetFilter SDK. 7 | // The code and information is provided "as-is" without 8 | // warranty of any kind, either expressed or implied. 9 | // 10 | 11 | #pragma once 12 | 13 | #include "sync.h" 14 | #include 15 | 16 | class ThreadJobSource 17 | { 18 | public: 19 | virtual void execute() = 0; 20 | virtual void threadStarted() = 0; 21 | virtual void threadStopped() = 0; 22 | }; 23 | 24 | class ThreadPool 25 | { 26 | public: 27 | ThreadPool() 28 | { 29 | m_stopEvent.Attach(CreateEvent(NULL, TRUE, FALSE, NULL)); 30 | m_pJobSource = NULL; 31 | } 32 | 33 | ~ThreadPool() 34 | { 35 | free(); 36 | } 37 | 38 | bool init(int threadCount, ThreadJobSource * pJobSource) 39 | { 40 | HANDLE hThread; 41 | unsigned threadId; 42 | int i; 43 | 44 | ResetEvent(m_stopEvent); 45 | 46 | m_pJobSource = pJobSource; 47 | 48 | if (threadCount <= 0) 49 | { 50 | SYSTEM_INFO sysinfo; 51 | GetSystemInfo( &sysinfo ); 52 | 53 | threadCount = sysinfo.dwNumberOfProcessors; 54 | if (threadCount == 0) 55 | { 56 | threadCount = 1; 57 | } 58 | } 59 | 60 | for (i=0; ithreadStarted(); 104 | 105 | for (;;) 106 | { 107 | DWORD res = WaitForMultipleObjects(2, handles, FALSE, INFINITE); 108 | 109 | if (res == (WAIT_OBJECT_0+1)) 110 | break; 111 | 112 | m_pJobSource->execute(); 113 | } 114 | 115 | m_pJobSource->threadStopped(); 116 | } 117 | 118 | static unsigned WINAPI _threadProc(void* pData) 119 | { 120 | (reinterpret_cast(pData))->threadProc(); 121 | return 0; 122 | } 123 | 124 | private: 125 | ThreadJobSource * m_pJobSource; 126 | 127 | typedef std::vector tThreads; 128 | tThreads m_threads; 129 | 130 | AutoEventHandle m_jobAvailableEvent; 131 | AutoHandle m_stopEvent; 132 | }; -------------------------------------------------------------------------------- /src/utf8.h: -------------------------------------------------------------------------------- 1 | #ifndef _UTF_8 2 | #define _UTF_8 3 | 4 | inline void encodeUTF8Char(std::string& str, wchar_t character) 5 | { 6 | unsigned int c = (unsigned int) character; 7 | 8 | // check for invalid chars 9 | if ((c >= 0xD800 && c <= 0xDFFF) || c == 0xFFFF || c == 0xFFFE || c >= 0x80000000) 10 | { 11 | // check for invalid sequence 12 | // NOTE 3 - Values of x in the range 0000 D800 .. 0000 DFFF 13 | // are reserved for the UTF-16 form and do not occur in UCS-4. 14 | // The values 0000 FFFE and 0000 FFFF also do not occur (see clause 8). 15 | // The mappings of these code positions in UTF-8 are undefined. 16 | c = 0xFFFD; 17 | } 18 | 19 | if (c < 0x80) 20 | { 21 | // x = 0000 0000 .. 0000 007F; x; 22 | str += (char) c; 23 | } 24 | else if (c < 0x800) 25 | { 26 | // x = 0000 0080 .. 0000 07FF; C0 + x/2**6; 27 | // 80 + x%2**6; 28 | str += (char) (0xC0 + (c >> 6)); 29 | str += (char) (0x80 + (c & 0x3F)); 30 | } 31 | // catch 16bit wchar_t here 32 | // anything after this is 32bit wchar_t 33 | else if (sizeof(wchar_t) == 2 || c < 0x10000) 34 | { 35 | // x = 0000 0800 .. 0000 FFFF; E0 + x/2**12; 36 | // 80 + x/2**6%2**6; 37 | // 80 + x%2**6; 38 | str += (char) (0xE0 + (c >> 12)); 39 | str += (char) (0x80 + ((c >> 6) & 0x3F)); 40 | str += (char) (0x80 + (c & 0x3F)); 41 | } 42 | else if (c < 0x200000) 43 | { 44 | // x = 0001 0000 .. 001F FFFF; F0 + x/2**18; 45 | // 80 + x/2**12%2**6; 46 | // 80 + x/2**6%2**6; 47 | // 80 + x%2**6; 48 | str += (char) (0xF0 + (c >> 18)); 49 | str += (char) (0x80 + ((c >> 12) & 0x3F)); 50 | str += (char) (0x80 + ((c >> 6) & 0x3F)); 51 | str += (char) (0x80 + (c & 0x3F)); 52 | } 53 | else if (c < 0x4000000) 54 | { 55 | // x = 0020 0000 .. 03FF FFFF; F8 + x/2**24; 56 | // 80 + x/2**18%2**6; 57 | // 80 + x/2**12%2**6; 58 | // 80 + x/2**6%2**6; 59 | // 80 + x%2**6; 60 | str += (char) (0xF8 + (c >> 24)); 61 | str += (char) (0x80 + ((c >> 18) & 0x3F)); 62 | str += (char) (0x80 + ((c >> 12) & 0x3F)); 63 | str += (char) (0x80 + ((c >> 6) & 0x3F)); 64 | str += (char) (0x80 + (c & 0x3F)); 65 | } 66 | else // if (c<0x80000000) 67 | { 68 | // x = 0400 0000 .. 7FFF FFFF; FC + x/2**30; 69 | // 80 + x/2**24%2**6; 70 | // 80 + x/2**18%2**6; 71 | // 80 + x/2**12%2**6; 72 | // 80 + x/2**6%2**6; 73 | // 80 + x%2**6; 74 | str += (char) (0xFC + (c >> 30)); 75 | str += (char) (0x80 + ((c >> 24) & 0x3F)); 76 | str += (char) (0x80 + ((c >> 18) & 0x3F)); 77 | str += (char) (0x80 + ((c >> 12) & 0x3F)); 78 | str += (char) (0x80 + ((c >> 6) & 0x3F)); 79 | str += (char) (0x80 + (c & 0x3F)); 80 | } 81 | } 82 | 83 | inline std::string encodeUTF8(const std::wstring& source) 84 | { 85 | std::string result; 86 | result.reserve(source.size() * 4 / 3); // optimization 87 | 88 | for (std::wstring::const_iterator it = source.begin(); it != source.end(); ++it) 89 | { 90 | encodeUTF8Char(result, (unsigned int) *it); 91 | } 92 | 93 | return result; 94 | } 95 | 96 | #define replacementChar 0xFFFD 97 | 98 | inline std::wstring decodeUTF8(const std::string& source) 99 | { 100 | unsigned int start = 0; 101 | 102 | std::wstring result; 103 | result.reserve(source.size()); 104 | 105 | for (unsigned int i = start; i < source.length(); i++) 106 | { 107 | unsigned char c = source[i]; 108 | 109 | wchar_t n; 110 | 111 | if (c != 0xFF && c != 0xFE) 112 | { 113 | int remainingBytes = (int)source.length() - i; 114 | int extraBytesForChar = -1; 115 | 116 | // check that character isn't a continuation byte 117 | if ((c >> 6) != 2) 118 | { 119 | // work out how many bytes the sequence is. 120 | // Bytes in sequence is equal to the number 121 | // 1 bits before the first 0. 122 | // e.g. 11100101 -> [1110] -> 3 123 | // 11110101 -> [11110] -> 4 124 | unsigned char d = c; 125 | 126 | // LHS contains sequence length. 127 | // RHS contains data. 128 | // dataMask is used to extract data. 129 | int dataMask = 0x7F; 130 | 131 | // Find sequence length 132 | while ((d & 0x80) != 0) 133 | { 134 | dataMask >>= 1; 135 | extraBytesForChar++; 136 | d <<= 1; 137 | } 138 | 139 | n = c & dataMask; 140 | 141 | // if there aren't enough bytes in the encoded sequence. 142 | if (extraBytesForChar > remainingBytes) 143 | { 144 | n = replacementChar; 145 | } 146 | else 147 | // decode sequence. 148 | for (int j = 0; j < extraBytesForChar; j++) 149 | { 150 | // update index & get continuation byte. 151 | c = source[++i]; 152 | 153 | if (c == 0xFF || c == 0xFE) 154 | { 155 | n = replacementChar; 156 | break; 157 | } 158 | 159 | // Make sure the continuation byte matchs 10xxxxxx. 160 | if ((c >> 6) == 2) 161 | { 162 | n = (n << 6) + (c&0x3F); 163 | } 164 | else 165 | { 166 | // revert index as this bytes wasn't a continuation, 167 | // so it might have been a start character. 168 | i--; 169 | n = replacementChar; 170 | break; 171 | } 172 | } 173 | } 174 | else 175 | { 176 | n = replacementChar; 177 | } 178 | 179 | // If the number of extra bytes in sequence is > 2 then it is a utf32 char. 180 | if (sizeof(wchar_t) == 2 && extraBytesForChar>2) 181 | { 182 | n = replacementChar; 183 | } 184 | else if (sizeof(wchar_t) == 4 && extraBytesForChar>5) 185 | { 186 | n = replacementChar; 187 | } 188 | } 189 | else 190 | { 191 | n = replacementChar; 192 | } 193 | 194 | // append the decoded character. 195 | result.append (1, n) ; 196 | } 197 | 198 | return result; 199 | } 200 | 201 | #endif --------------------------------------------------------------------------------