comparison src/net/sourceforge/jsocks/ProxyServer.java @ 349:205ee2873330

update jsocks to 2011-03-19
author Carl Byington <carl@five-ten-sg.com>
date Fri, 01 Aug 2014 11:23:10 -0700
parents 0ce5cc452d02
children
comparison
equal deleted inserted replaced
348:29076621bab0 349:205ee2873330
1 package net.sourceforge.jsocks; 1 package net.sourceforge.jsocks;
2 import java.io.EOFException;
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.io.InterruptedIOException;
6 import java.io.OutputStream;
7 import java.io.PrintStream;
8 import java.io.PushbackInputStream;
9 import java.net.ConnectException;
10 import java.net.InetAddress;
11 import java.net.NoRouteToHostException;
12 import java.net.ServerSocket;
13 import java.net.Socket;
14
15 import net.sourceforge.jsocks.server.ServerAuthenticator; 2 import net.sourceforge.jsocks.server.ServerAuthenticator;
3 import java.net.*;
4 import java.io.*;
16 5
17 /** 6 /**
18 SOCKS4 and SOCKS5 proxy, handles both protocols simultaniously. 7 SOCKS4 and SOCKS5 proxy, handles both protocols simultaniously.
19 Implements all SOCKS commands, including UDP relaying. 8 Implements all SOCKS commands, including UDP relaying.
20 <p> 9 <p>
25 in the world. One should never use this authentication scheme unless 14 in the world. One should never use this authentication scheme unless
26 one have pretty good reason to do so. 15 one have pretty good reason to do so.
27 There is a couple of other authentication schemes in socks.server package. 16 There is a couple of other authentication schemes in socks.server package.
28 @see socks.server.ServerAuthenticator 17 @see socks.server.ServerAuthenticator
29 */ 18 */
30 public class ProxyServer implements Runnable { 19 public class ProxyServer implements Runnable{
31 20
32 ServerAuthenticator auth; 21 ServerAuthenticator auth;
33 ProxyMessage msg = null; 22 ProxyMessage msg = null;
34 23
35 Socket sock = null, remote_sock = null; 24 Socket sock=null,remote_sock=null;
36 ServerSocket ss = null; 25 ServerSocket ss=null;
37 UDPRelayServer relayServer = null; 26 UDPRelayServer relayServer = null;
38 InputStream in, remote_in; 27 InputStream in,remote_in;
39 OutputStream out, remote_out; 28 OutputStream out,remote_out;
40 29
41 int mode; 30 int mode;
42 static final int START_MODE = 0; 31 static final int START_MODE = 0;
43 static final int ACCEPT_MODE = 1; 32 static final int ACCEPT_MODE = 1;
44 static final int PIPE_MODE = 2; 33 static final int PIPE_MODE = 2;
45 static final int ABORT_MODE = 3; 34 static final int ABORT_MODE = 3;
46 35
47 static final int BUF_SIZE = 8192; 36 static final int BUF_SIZE = 8192;
48 37
49 Thread pipe_thread1, pipe_thread2; 38 Thread pipe_thread1,pipe_thread2;
50 long lastReadTime; 39 long lastReadTime;
51 40
52 protected static int iddleTimeout = 180000; //3 minutes 41 static int iddleTimeout = 180000; //3 minutes
53 static int acceptTimeout = 180000; //3 minutes 42 static int acceptTimeout = 180000; //3 minutes
54 43
55 static PrintStream log = null; 44 static PrintStream log = null;
56 static Proxy proxy; 45 static CProxy proxy;
57 46
58 47
59 //Public Constructors 48 //Public Constructors
60 ///////////////////// 49 /////////////////////
61 50
62 51
63 /** 52 /**
64 Creates a proxy server with given Authentication scheme. 53 Creates a proxy server with given Authentication scheme.
65 @param auth Authentication scheme to be used. 54 @param auth Authentication scheme to be used.
66 */ 55 */
67 public ProxyServer(ServerAuthenticator auth) { 56 public ProxyServer(ServerAuthenticator auth){
68 this.auth = auth; 57 this.auth = auth;
69 } 58 }
70 59
71 //Other constructors 60 //Other constructors
72 //////////////////// 61 ////////////////////
73 62
74 protected ProxyServer(ServerAuthenticator auth, Socket s) { 63 ProxyServer(ServerAuthenticator auth,Socket s){
75 this.auth = auth; 64 this.auth = auth;
76 this.sock = s; 65 this.sock = s;
77 mode = START_MODE; 66 mode = START_MODE;
78 } 67 }
79 68
80 //Public methods 69 //Public methods
81 ///////////////// 70 /////////////////
82 71
83 /** 72 /**
84 Set the logging stream. Specifying null disables logging. 73 Set the logging stream. Specifying null disables logging.
74 */
75 public static void setLog(OutputStream out){
76 if(out == null){
77 log = null;
78 }else{
79 log = new PrintStream(out,true);
80 }
81
82 UDPRelayServer.log = log;
83 }
84
85 /**
86 Set proxy.
87 <p>
88 Allows CProxy chaining so that one CProxy server is connected to another
89 and so on. If proxy supports SOCKSv4, then only some SOCKSv5 requests
90 can be handled, UDP would not work, however CONNECT and BIND will be
91 translated.
92
93 @param p CProxy which should be used to handle user requests.
94 */
95 public static void setProxy(CProxy p){
96 proxy =p;
97 UDPRelayServer.proxy = proxy;
98 }
99
100 /**
101 Get proxy.
102 @return CProxy wich is used to handle user requests.
103 */
104 public static CProxy getProxy(){
105 return proxy;
106 }
107
108 /**
109 Sets the timeout for connections, how long shoud server wait
110 for data to arrive before dropping the connection.<br>
111 Zero timeout implies infinity.<br>
112 Default timeout is 3 minutes.
113 */
114 public static void setIddleTimeout(int timeout){
115 iddleTimeout = timeout;
116 }
117 /**
118 Sets the timeout for BIND command, how long the server should
119 wait for the incoming connection.<br>
120 Zero timeout implies infinity.<br>
121 Default timeout is 3 minutes.
122 */
123 public static void setAcceptTimeout(int timeout){
124 acceptTimeout = timeout;
125 }
126
127 /**
128 Sets the timeout for UDPRelay server.<br>
129 Zero timeout implies infinity.<br>
130 Default timeout is 3 minutes.
131 */
132 public static void setUDPTimeout(int timeout){
133 UDPRelayServer.setTimeout(timeout);
134 }
135
136 /**
137 Sets the size of the datagrams used in the UDPRelayServer.<br>
138 Default size is 64K, a bit more than maximum possible size of the
139 datagram.
85 */ 140 */
86 public static void setLog(OutputStream out) { 141 public static void setDatagramSize(int size){
87 if (out == null) { 142 UDPRelayServer.setDatagramSize(size);
88 log = null; 143 }
144
145
146 /**
147 Start the CProxy server at given port.<br>
148 This methods blocks.
149 */
150 public void start(int port){
151 start(port,5,null);
152 }
153
154 /**
155 Create a server with the specified port, listen backlog, and local
156 IP address to bind to. The localIP argument can be used on a multi-homed
157 host for a ServerSocket that will only accept connect requests to one of
158 its addresses. If localIP is null, it will default accepting connections
159 on any/all local addresses. The port must be between 0 and 65535,
160 inclusive. <br>
161 This methods blocks.
162 */
163 public void start(int port,int backlog,InetAddress localIP){
164 try{
165 ss = new ServerSocket(port,backlog,localIP);
166 log("Starting SOCKS Proxy on:"+ss.getInetAddress().getHostAddress()+":"
167 +ss.getLocalPort());
168 while(true){
169 Socket s = ss.accept();
170 log("Accepted from:"+s.getInetAddress().getHostName()+":"
171 +s.getPort());
172 ProxyServer ps = new ProxyServer(auth,s);
173 (new Thread(ps)).start();
174 }
175 }catch(IOException ioe){
176 ioe.printStackTrace();
177 }finally{
178 }
179 }
180
181 /**
182 Stop server operation.It would be wise to interrupt thread running the
183 server afterwards.
184 */
185 public void stop(){
186 try{
187 if(ss != null) ss.close();
188 }catch(IOException ioe){
189 }
190 }
191
192 //Runnable interface
193 ////////////////////
194 public void run(){
195 switch(mode){
196 case START_MODE:
197 try{
198 startSession();
199 }catch(IOException ioe){
200 handleException(ioe);
201 //ioe.printStackTrace();
202 }finally{
203 abort();
204 if(auth!=null) auth.endSession();
205 log("Main thread(client->remote)stopped.");
206 }
207 break;
208 case ACCEPT_MODE:
209 try{
210 doAccept();
211 mode = PIPE_MODE;
212 pipe_thread1.interrupt(); //Tell other thread that connection have
213 //been accepted.
214 pipe(remote_in,out);
215 }catch(IOException ioe){
216 //log("Accept exception:"+ioe);
217 handleException(ioe);
218 }finally{
219 abort();
220 log("Accept thread(remote->client) stopped");
221 }
222 break;
223 case PIPE_MODE:
224 try{
225 pipe(remote_in,out);
226 }catch(IOException ioe){
227 }finally{
228 abort();
229 log("Support thread(remote->client) stopped");
230 }
231 break;
232 case ABORT_MODE:
233 break;
234 default:
235 log("Unexpected MODE "+mode);
236 }
237 }
238
239 //Private methods
240 /////////////////
241 private void startSession() throws IOException{
242 sock.setSoTimeout(iddleTimeout);
243
244 try{
245 auth = auth.startSession(sock);
246 }catch(IOException ioe){
247 log("Auth throwed exception:"+ioe);
248 auth = null;
249 return;
250 }
251
252 if(auth == null){ //Authentication failed
253 log("Authentication failed");
254 return;
255 }
256
257 in = auth.getInputStream();
258 out = auth.getOutputStream();
259
260 msg = readMsg(in);
261 handleRequest(msg);
262 }
263
264 private void handleRequest(ProxyMessage msg)
265 throws IOException{
266 if(!auth.checkRequest(msg)) throw new
267 SocksException(CProxy.SOCKS_FAILURE);
268
269 if(msg.ip == null){
270 if(msg instanceof Socks5Message){
271 msg.ip = InetAddress.getByName(msg.host);
272 }else
273 throw new SocksException(CProxy.SOCKS_FAILURE);
274 }
275 log(msg);
276
277 switch(msg.command){
278 case CProxy.SOCKS_CMD_CONNECT:
279 onConnect(msg);
280 break;
281 case CProxy.SOCKS_CMD_BIND:
282 onBind(msg);
283 break;
284 case CProxy.SOCKS_CMD_UDP_ASSOCIATE:
285 onUDP(msg);
286 break;
287 default:
288 throw new SocksException(CProxy.SOCKS_CMD_NOT_SUPPORTED);
289 }
290 }
291
292 private void handleException(IOException ioe){
293 //If we couldn't read the request, return;
294 if(msg == null) return;
295 //If have been aborted by other thread
296 if(mode == ABORT_MODE) return;
297 //If the request was successfully completed, but exception happened later
298 if(mode == PIPE_MODE) return;
299
300 int error_code = CProxy.SOCKS_FAILURE;
301
302 if(ioe instanceof SocksException)
303 error_code = ((SocksException)ioe).errCode;
304 else if(ioe instanceof NoRouteToHostException)
305 error_code = CProxy.SOCKS_HOST_UNREACHABLE;
306 else if(ioe instanceof ConnectException)
307 error_code = CProxy.SOCKS_CONNECTION_REFUSED;
308 else if(ioe instanceof InterruptedIOException)
309 error_code = CProxy.SOCKS_TTL_EXPIRE;
310
311 if(error_code > CProxy.SOCKS_ADDR_NOT_SUPPORTED || error_code < 0){
312 error_code = CProxy.SOCKS_FAILURE;
313 }
314
315 sendErrorMessage(error_code);
316 }
317
318 private void onConnect(ProxyMessage msg) throws IOException {
319 Socket s = null;
320 ProxyMessage response = null;
321 int iSock5Cmd = CProxy.SOCKS_FAILURE; //defaulting to failure
322 int iSock4Msg = Socks4Message.REPLY_NO_CONNECT;
323 InetAddress sIp = null; int iPort = 0;
324
325 try {
326 if (proxy == null) {
327 s = new Socket(msg.ip, msg.port);
328 } else {
329 s = new SocksSocket(proxy, msg.ip, msg.port);
330 }
331 log("Connected to " + s.getInetAddress() + ":" + s.getPort());
332
333 iSock5Cmd = CProxy.SOCKS_SUCCESS; iSock4Msg = Socks4Message.REPLY_OK;
334 sIp = s.getInetAddress(); iPort = s.getPort();
335
336 }
337 catch (Exception sE) {
338 log("Failed connecting to remote socket. Exception: " + sE.getLocalizedMessage());
339
340 //TBD Pick proper socks error for corresponding socket error, below is too generic
341 iSock5Cmd = CProxy.SOCKS_CONNECTION_REFUSED; iSock4Msg = Socks4Message.REPLY_NO_CONNECT;
342 }
343
344 if (msg instanceof Socks5Message) {
345 response = new Socks5Message(iSock5Cmd, sIp, iPort);
346 } else {
347 response = new Socks4Message(iSock4Msg, sIp, iPort);
348 }
349
350 response.write(out);
351
352 if (s != null) {
353 startPipe(s);
89 } 354 }
90 else { 355 else {
91 log = new PrintStream(out, true); 356 throw (new RuntimeException("onConnect() Failed to create Socket()"));
92 } 357 }
93 358
94 UDPRelayServer.log = log; 359 return;
95 } 360 }
96 361
97 /** 362
98 Set proxy. 363 private void onBind(ProxyMessage msg) throws IOException{
99 <p> 364 ProxyMessage response = null;
100 Allows Proxy chaining so that one Proxy server is connected to another 365
101 and so on. If proxy supports SOCKSv4, then only some SOCKSv5 requests 366 if(proxy == null)
102 can be handled, UDP would not work, however CONNECT and BIND will be 367 ss = new ServerSocket(0);
103 translated. 368 else
104 369 ss = new SocksServerSocket(proxy, msg.ip, msg.port);
105 @param p Proxy which should be used to handle user requests. 370
106 */ 371 ss.setSoTimeout(acceptTimeout);
107 public static void setProxy(Proxy p) { 372
108 proxy = p; 373 log("Trying accept on "+ss.getInetAddress()+":"+ss.getLocalPort());
109 UDPRelayServer.proxy = proxy; 374
110 } 375 if(msg.version == 5)
111 376 response = new Socks5Message(CProxy.SOCKS_SUCCESS,ss.getInetAddress(),
112 /** 377 ss.getLocalPort());
113 Get proxy. 378 else
114 @return Proxy wich is used to handle user requests. 379 response = new Socks4Message(Socks4Message.REPLY_OK,
115 */ 380 ss.getInetAddress(),
116 public static Proxy getProxy() { 381 ss.getLocalPort());
117 return proxy; 382 response.write(out);
118 } 383
119 384 mode = ACCEPT_MODE;
120 /** 385
121 Sets the timeout for connections, how long shoud server wait 386 pipe_thread1 = Thread.currentThread();
122 for data to arrive before dropping the connection.<br> 387 pipe_thread2 = new Thread(this);
123 Zero timeout implies infinity.<br> 388 pipe_thread2.start();
124 Default timeout is 3 minutes. 389
125 */ 390 //Make timeout infinit.
126 public static void setIddleTimeout(int timeout) { 391 sock.setSoTimeout(0);
127 iddleTimeout = timeout; 392 int eof=0;
128 } 393
129 /** 394 try{
130 Sets the timeout for BIND command, how long the server should 395 while((eof=in.read())>=0){
131 wait for the incoming connection.<br> 396 if(mode != ACCEPT_MODE){
132 Zero timeout implies infinity.<br> 397 if(mode != PIPE_MODE) return;//Accept failed
133 Default timeout is 3 minutes. 398
134 */ 399 remote_out.write(eof);
135 public static void setAcceptTimeout(int timeout) { 400 break;
136 acceptTimeout = timeout; 401 }
137 }
138
139 /**
140 Sets the timeout for UDPRelay server.<br>
141 Zero timeout implies infinity.<br>
142 Default timeout is 3 minutes.
143 */
144 public static void setUDPTimeout(int timeout) {
145 UDPRelayServer.setTimeout(timeout);
146 }
147
148 /**
149 Sets the size of the datagrams used in the UDPRelayServer.<br>
150 Default size is 64K, a bit more than maximum possible size of the
151 datagram.
152 */
153 public static void setDatagramSize(int size) {
154 UDPRelayServer.setDatagramSize(size);
155 }
156
157
158 /**
159 Start the Proxy server at given port.<br>
160 This methods blocks.
161 */
162 public void start(int port) {
163 start(port, 5, null);
164 }
165
166 /**
167 Create a server with the specified port, listen backlog, and local
168 IP address to bind to. The localIP argument can be used on a multi-homed
169 host for a ServerSocket that will only accept connect requests to one of
170 its addresses. If localIP is null, it will default accepting connections
171 on any/all local addresses. The port must be between 0 and 65535,
172 inclusive. <br>
173 This methods blocks.
174 */
175 public void start(int port, int backlog, InetAddress localIP) {
176 try {
177 ss = new ServerSocket(port, backlog, localIP);
178 log("Starting SOCKS Proxy on:" + ss.getInetAddress().getHostAddress() + ":"
179 + ss.getLocalPort());
180
181 while (true) {
182 Socket s = ss.accept();
183 log("Accepted from:" + s.getInetAddress().getHostName() + ":"
184 + s.getPort());
185 ProxyServer ps = new ProxyServer(auth, s);
186 (new Thread(ps)).start();
187 }
188 } 402 }
189 catch (IOException ioe) { 403 }catch(EOFException eofe){
190 ioe.printStackTrace(); 404 //System.out.println("EOF exception");
191 } 405 return;//Connection closed while we were trying to accept.
192 finally { 406 }catch(InterruptedIOException iioe){
193 } 407 //Accept thread interrupted us.
194 } 408 //System.out.println("Interrupted");
195 409 if(mode != PIPE_MODE)
196 /** 410 return;//If accept thread was not successfull return.
197 Stop server operation.It would be wise to interrupt thread running the 411 }finally{
198 server afterwards. 412 //System.out.println("Finnaly!");
199 */ 413 }
200 public void stop() { 414
201 try { 415 if(eof < 0)//Connection closed while we were trying to accept;
202 if (ss != null) ss.close(); 416 return;
203 } 417
204 catch (IOException ioe) { 418 //Do not restore timeout, instead timeout is set on the
205 } 419 //remote socket. It does not make any difference.
206 } 420
207 421 pipe(in,remote_out);
208 //Runnable interface 422 }
209 //////////////////// 423
210 public void run() { 424 private void onUDP(ProxyMessage msg) throws IOException{
211 switch (mode) { 425 if(msg.ip.getHostAddress().equals("0.0.0.0"))
212 case START_MODE: 426 msg.ip = sock.getInetAddress();
213 try { 427 log("Creating UDP relay server for "+msg.ip+":"+msg.port);
214 startSession(); 428 relayServer = new UDPRelayServer(msg.ip,msg.port,
215 } 429 Thread.currentThread(),sock,auth);
216 catch (IOException ioe) { 430
217 handleException(ioe); 431 ProxyMessage response;
218 //ioe.printStackTrace(); 432
219 } 433 response = new Socks5Message(CProxy.SOCKS_SUCCESS,
220 finally { 434 relayServer.relayIP,relayServer.relayPort);
221 abort(); 435
222 436 response.write(out);
223 if (auth != null) auth.endSession(); 437
224 438 relayServer.start();
225 log("Main thread(client->remote)stopped."); 439
226 } 440 //Make timeout infinit.
227 441 sock.setSoTimeout(0);
228 break; 442 try{
229 443 while(in.read()>=0) /*do nothing*/;
230 case ACCEPT_MODE: 444 }catch(EOFException eofe){
231 try { 445 }
232 doAccept(); 446 }
233 mode = PIPE_MODE;
234 pipe_thread1.interrupt(); //Tell other thread that connection have
235 //been accepted.
236 pipe(remote_in, out);
237 }
238 catch (IOException ioe) {
239 //log("Accept exception:"+ioe);
240 handleException(ioe);
241 }
242 finally {
243 abort();
244 log("Accept thread(remote->client) stopped");
245 }
246
247 break;
248
249 case PIPE_MODE:
250 try {
251 pipe(remote_in, out);
252 }
253 catch (IOException ioe) {
254 }
255 finally {
256 abort();
257 log("Support thread(remote->client) stopped");
258 }
259
260 break;
261
262 case ABORT_MODE:
263 break;
264
265 default:
266 log("Unexpected MODE " + mode);
267 }
268 }
269
270 //Private methods
271 /////////////////
272 private void startSession() throws IOException {
273 sock.setSoTimeout(iddleTimeout);
274
275 try {
276 auth = auth.startSession(sock);
277 }
278 catch (IOException ioe) {
279 log("Auth throwed exception:" + ioe);
280 auth = null;
281 return;
282 }
283
284 if (auth == null) { //Authentication failed
285 log("Authentication failed");
286 return;
287 }
288
289 in = auth.getInputStream();
290 out = auth.getOutputStream();
291 msg = readMsg(in);
292 handleRequest(msg);
293 }
294
295 protected void handleRequest(ProxyMessage msg)
296 throws IOException {
297 if (!auth.checkRequest(msg)) throw new
298 SocksException(Proxy.SOCKS_FAILURE);
299
300 if (msg.ip == null) {
301 if (msg instanceof Socks5Message) {
302 msg.ip = InetAddress.getByName(msg.host);
303 }
304 else
305 throw new SocksException(Proxy.SOCKS_FAILURE);
306 }
307
308 log(msg);
309
310 switch (msg.command) {
311 case Proxy.SOCKS_CMD_CONNECT:
312 onConnect(msg);
313 break;
314
315 case Proxy.SOCKS_CMD_BIND:
316 onBind(msg);
317 break;
318
319 case Proxy.SOCKS_CMD_UDP_ASSOCIATE:
320 onUDP(msg);
321 break;
322
323 default:
324 throw new SocksException(Proxy.SOCKS_CMD_NOT_SUPPORTED);
325 }
326 }
327
328 private void handleException(IOException ioe) {
329 //If we couldn't read the request, return;
330 if (msg == null) return;
331
332 //If have been aborted by other thread
333 if (mode == ABORT_MODE) return;
334
335 //If the request was successfully completed, but exception happened later
336 if (mode == PIPE_MODE) return;
337
338 int error_code = Proxy.SOCKS_FAILURE;
339
340 if (ioe instanceof SocksException)
341 error_code = ((SocksException)ioe).errCode;
342 else if (ioe instanceof NoRouteToHostException)
343 error_code = Proxy.SOCKS_HOST_UNREACHABLE;
344 else if (ioe instanceof ConnectException)
345 error_code = Proxy.SOCKS_CONNECTION_REFUSED;
346 else if (ioe instanceof InterruptedIOException)
347 error_code = Proxy.SOCKS_TTL_EXPIRE;
348
349 if (error_code > Proxy.SOCKS_ADDR_NOT_SUPPORTED || error_code < 0) {
350 error_code = Proxy.SOCKS_FAILURE;
351 }
352
353 sendErrorMessage(error_code);
354 }
355
356 private void onConnect(ProxyMessage msg) throws IOException {
357 Socket s;
358 ProxyMessage response = null;
359 s = new Socket(msg.ip, msg.port);
360 log("Connected to " + s.getInetAddress() + ":" + s.getPort());
361
362 if (msg instanceof Socks5Message) {
363 response = new Socks5Message(Proxy.SOCKS_SUCCESS,
364 s.getLocalAddress(),
365 s.getLocalPort());
366 }
367 else {
368 response = new Socks4Message(Socks4Message.REPLY_OK,
369 s.getLocalAddress(), s.getLocalPort());
370 }
371
372 response.write(out);
373 startPipe(s);
374 }
375
376 private void onBind(ProxyMessage msg) throws IOException {
377 ProxyMessage response = null;
378
379 if (proxy == null)
380 ss = new ServerSocket(0);
381 else
382 ss = new SocksServerSocket(proxy, msg.ip, msg.port);
383
384 ss.setSoTimeout(acceptTimeout);
385 log("Trying accept on " + ss.getInetAddress() + ":" + ss.getLocalPort());
386
387 if (msg.version == 5)
388 response = new Socks5Message(Proxy.SOCKS_SUCCESS, ss.getInetAddress(),
389 ss.getLocalPort());
390 else
391 response = new Socks4Message(Socks4Message.REPLY_OK,
392 ss.getInetAddress(),
393 ss.getLocalPort());
394
395 response.write(out);
396 mode = ACCEPT_MODE;
397 pipe_thread1 = Thread.currentThread();
398 pipe_thread2 = new Thread(this);
399 pipe_thread2.start();
400 //Make timeout infinit.
401 sock.setSoTimeout(0);
402 int eof = 0;
403
404 try {
405 while ((eof = in.read()) >= 0) {
406 if (mode != ACCEPT_MODE) {
407 if (mode != PIPE_MODE) return; //Accept failed
408
409 remote_out.write(eof);
410 break;
411 }
412 }
413 }
414 catch (EOFException eofe) {
415 //System.out.println("EOF exception");
416 return;//Connection closed while we were trying to accept.
417 }
418 catch (InterruptedIOException iioe) {
419 //Accept thread interrupted us.
420 //System.out.println("Interrupted");
421 if (mode != PIPE_MODE)
422 return;//If accept thread was not successfull return.
423 }
424 finally {
425 //System.out.println("Finnaly!");
426 }
427
428 if (eof < 0) //Connection closed while we were trying to accept;
429 return;
430
431 //Do not restore timeout, instead timeout is set on the
432 //remote socket. It does not make any difference.
433 pipe(in, remote_out);
434 }
435
436 private void onUDP(ProxyMessage msg) throws IOException {
437 if (msg.ip.getHostAddress().equals("0.0.0.0"))
438 msg.ip = sock.getInetAddress();
439
440 log("Creating UDP relay server for " + msg.ip + ":" + msg.port);
441 relayServer = new UDPRelayServer(msg.ip, msg.port,
442 Thread.currentThread(), sock, auth);
443 ProxyMessage response;
444 response = new Socks5Message(Proxy.SOCKS_SUCCESS,
445 relayServer.relayIP, relayServer.relayPort);
446 response.write(out);
447 relayServer.start();
448 //Make timeout infinit.
449 sock.setSoTimeout(0);
450
451 try {
452 while (in.read() >= 0) /*do nothing*/;
453 }
454 catch (EOFException eofe) {
455 }
456 }
457 447
458 //Private methods 448 //Private methods
459 ////////////////// 449 //////////////////
460 450
461 private void doAccept() throws IOException { 451 private void doAccept() throws IOException{
462 Socket s; 452 Socket s;
463 long startTime = System.currentTimeMillis(); 453 long startTime = System.currentTimeMillis();
464 454
465 while (true) { 455 while(true){
466 s = ss.accept(); 456 s = ss.accept();
467 457 if(s.getInetAddress().equals(msg.ip)){
468 if (s.getInetAddress().equals(msg.ip)) { 458 //got the connection from the right host
469 //got the connection from the right host 459 //Close listenning socket.
470 //Close listenning socket. 460 ss.close();
471 ss.close(); 461 break;
472 break; 462 }else if(ss instanceof SocksServerSocket){
463 //We can't accept more then one connection
464 s.close();
465 ss.close();
466 throw new SocksException(CProxy.SOCKS_FAILURE);
467 }else{
468 if(acceptTimeout!=0){ //If timeout is not infinit
469 int newTimeout = acceptTimeout-(int)(System.currentTimeMillis()-
470 startTime);
471 if(newTimeout <= 0) throw new InterruptedIOException(
472 "In doAccept()");
473 ss.setSoTimeout(newTimeout);
473 } 474 }
474 else if (ss instanceof SocksServerSocket) { 475 s.close(); //Drop all connections from other hosts
475 //We can't accept more then one connection 476 }
476 s.close(); 477 }
477 ss.close(); 478
478 throw new SocksException(Proxy.SOCKS_FAILURE); 479 //Accepted connection
479 } 480 remote_sock = s;
480 else { 481 remote_in = s.getInputStream();
481 if (acceptTimeout != 0) { //If timeout is not infinit 482 remote_out = s.getOutputStream();
482 int newTimeout = acceptTimeout - (int)(System.currentTimeMillis() - 483
483 startTime); 484 //Set timeout
484 485 remote_sock.setSoTimeout(iddleTimeout);
485 if (newTimeout <= 0) throw new InterruptedIOException( 486
486 "In doAccept()"); 487 log("Accepted from "+s.getInetAddress()+":"+s.getPort());
487 488
488 ss.setSoTimeout(newTimeout); 489 ProxyMessage response;
489 } 490
490 491 if(msg.version == 5)
491 s.close(); //Drop all connections from other hosts 492 response = new Socks5Message(CProxy.SOCKS_SUCCESS, s.getInetAddress(),
492 } 493 s.getPort());
493 } 494 else
494 495 response = new Socks4Message(Socks4Message.REPLY_OK,
495 //Accepted connection 496 s.getInetAddress(), s.getPort());
496 remote_sock = s; 497 response.write(out);
497 remote_in = s.getInputStream(); 498 }
498 remote_out = s.getOutputStream(); 499
499 //Set timeout 500 private ProxyMessage readMsg(InputStream in) throws IOException{
500 remote_sock.setSoTimeout(iddleTimeout); 501 PushbackInputStream push_in;
501 log("Accepted from " + s.getInetAddress() + ":" + s.getPort()); 502 if(in instanceof PushbackInputStream)
502 ProxyMessage response; 503 push_in = (PushbackInputStream) in;
503 504 else
504 if (msg.version == 5) 505 push_in = new PushbackInputStream(in);
505 response = new Socks5Message(Proxy.SOCKS_SUCCESS, s.getInetAddress(), 506
506 s.getPort()); 507 int version = push_in.read();
507 else 508 push_in.unread(version);
508 response = new Socks4Message(Socks4Message.REPLY_OK, 509
509 s.getInetAddress(), s.getPort()); 510
510 511 ProxyMessage msg;
511 response.write(out); 512
512 } 513 if(version == 5){
513 514 msg = new Socks5Message(push_in,false);
514 protected ProxyMessage readMsg(InputStream in) throws IOException { 515 }else if(version == 4){
515 PushbackInputStream push_in; 516 msg = new Socks4Message(push_in,false);
516 517 }else{
517 if (in instanceof PushbackInputStream) 518 throw new SocksException(CProxy.SOCKS_FAILURE);
518 push_in = (PushbackInputStream) in; 519 }
519 else 520 return msg;
520 push_in = new PushbackInputStream(in); 521 }
521 522
522 int version = push_in.read(); 523 private void startPipe(Socket s){
523 push_in.unread(version); 524 mode = PIPE_MODE;
524 ProxyMessage msg; 525 remote_sock = s;
525 526 try{
526 if (version == 5) { 527 remote_in = s.getInputStream();
527 msg = new Socks5Message(push_in, false); 528 remote_out = s.getOutputStream();
528 } 529 pipe_thread1 = Thread.currentThread();
529 else if (version == 4) { 530 pipe_thread2 = new Thread(this);
530 msg = new Socks4Message(push_in, false); 531 pipe_thread2.start();
531 } 532 pipe(in,remote_out);
532 else { 533 }catch(IOException ioe){
533 throw new SocksException(Proxy.SOCKS_FAILURE); 534 }
534 } 535 }
535 536
536 return msg; 537 private void sendErrorMessage(int error_code){
537 } 538 ProxyMessage err_msg;
538 539 if(msg instanceof Socks4Message)
539 private void startPipe(Socket s) { 540 err_msg = new Socks4Message(Socks4Message.REPLY_REJECTED);
540 mode = PIPE_MODE; 541 else
541 remote_sock = s; 542 err_msg = new Socks5Message(error_code);
542 543 try{
543 try { 544 err_msg.write(out);
544 remote_in = s.getInputStream(); 545 }catch(IOException ioe){}
545 remote_out = s.getOutputStream(); 546 }
546 pipe_thread1 = Thread.currentThread(); 547
547 pipe_thread2 = new Thread(this); 548 private synchronized void abort(){
548 pipe_thread2.start(); 549 if(mode == ABORT_MODE) return;
549 pipe(in, remote_out); 550 mode = ABORT_MODE;
550 } 551 try{
551 catch (IOException ioe) { 552 log("Aborting operation");
552 } 553 if(remote_sock != null) remote_sock.close();
553 } 554 if(sock != null) sock.close();
554 555 if(relayServer!=null) relayServer.stop();
555 private void sendErrorMessage(int error_code) { 556 if(ss!=null) ss.close();
556 ProxyMessage err_msg; 557 if(pipe_thread1 != null) pipe_thread1.interrupt();
557 558 if(pipe_thread2 != null) pipe_thread2.interrupt();
558 if (msg instanceof Socks4Message) 559 }catch(IOException ioe){}
559 err_msg = new Socks4Message(Socks4Message.REPLY_REJECTED); 560 }
560 else 561
561 err_msg = new Socks5Message(error_code); 562 static final void log(String s){
562 563 if(log != null){
563 try { 564 log.println(s);
564 err_msg.write(out); 565 log.flush();
565 } 566 }
566 catch (IOException ioe) {} 567 }
567 } 568
568 569 static final void log(ProxyMessage msg){
569 private synchronized void abort() { 570 log("Request version:"+msg.version+
570 if (mode == ABORT_MODE) return; 571 "\tCommand: "+command2String(msg.command));
571 572 log("IP:"+msg.ip +"\tPort:"+msg.port+
572 mode = ABORT_MODE; 573 (msg.version==4?"\tUser:"+msg.user:""));
573 574 }
574 try { 575
575 log("Aborting operation"); 576 private void pipe(InputStream in,OutputStream out) throws IOException{
576 577 lastReadTime = System.currentTimeMillis();
577 if (remote_sock != null) remote_sock.close(); 578 byte[] buf = new byte[BUF_SIZE];
578 579 int len = 0;
579 if (sock != null) sock.close(); 580 while(len >= 0){
580 581 try{
581 if (relayServer != null) relayServer.stop(); 582 if(len!=0){
582 583 out.write(buf,0,len);
583 if (ss != null) ss.close(); 584 out.flush();
584 585 }
585 if (pipe_thread1 != null) pipe_thread1.interrupt(); 586 len= in.read(buf);
586 587 lastReadTime = System.currentTimeMillis();
587 if (pipe_thread2 != null) pipe_thread2.interrupt(); 588 }catch(InterruptedIOException iioe){
588 } 589 if(iddleTimeout == 0) return;//Other thread interrupted us.
589 catch (IOException ioe) {} 590 long timeSinceRead = System.currentTimeMillis() - lastReadTime;
590 } 591 if(timeSinceRead >= iddleTimeout - 1000) //-1s for adjustment.
591 592 return;
592 static final void log(String s) { 593 len = 0;
593 if (log != null) { 594
594 log.println(s); 595 }
595 log.flush(); 596 }
596 } 597 }
597 } 598 static final String command_names[] = {"CONNECT","BIND","UDP_ASSOCIATE"};
598 599
599 static final void log(ProxyMessage msg) { 600 static final String command2String(int cmd){
600 log("Request version:" + msg.version + 601 if(cmd > 0 && cmd < 4) return command_names[cmd-1];
601 "\tCommand: " + command2String(msg.command)); 602 else return "Unknown Command "+cmd;
602 log("IP:" + msg.ip + "\tPort:" + msg.port + 603 }
603 (msg.version == 4 ? "\tUser:" + msg.user : ""));
604 }
605
606 private void pipe(InputStream in, OutputStream out) throws IOException {
607 lastReadTime = System.currentTimeMillis();
608 byte[] buf = new byte[BUF_SIZE];
609 int len = 0;
610
611 while (len >= 0) {
612 try {
613 if (len != 0) {
614 out.write(buf, 0, len);
615 out.flush();
616 }
617
618 len = in.read(buf);
619 lastReadTime = System.currentTimeMillis();
620 }
621 catch (InterruptedIOException iioe) {
622 if (iddleTimeout == 0) return; //Other thread interrupted us.
623
624 long timeSinceRead = System.currentTimeMillis() - lastReadTime;
625
626 if (timeSinceRead >= iddleTimeout - 1000) //-1s for adjustment.
627 return;
628
629 len = 0;
630 }
631 }
632 }
633 static final String command_names[] = {"CONNECT", "BIND", "UDP_ASSOCIATE"};
634
635 static final String command2String(int cmd) {
636 if (cmd > 0 && cmd < 4) return command_names[cmd - 1];
637 else return "Unknown Command " + cmd;
638 }
639 } 604 }