1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 package HTTPClient;
34
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.io.OutputStream;
38 import java.io.ByteArrayOutputStream;
39 import java.net.Socket;
40 import java.net.InetAddress;
41 import java.net.SocketException;
42 import java.net.UnknownHostException;
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 class SocksClient
64 {
65
66 private String socks_host;
67
68
69 private int socks_port;
70
71
72 private int socks_version;
73
74
75 private final static byte CONNECT = 1,
76 BIND = 2,
77 UDP_ASS = 3;
78
79
80 private final static byte NO_AUTH = 0,
81 GSSAPI = 1,
82 USERPWD = 2,
83 NO_ACC = (byte) 0xFF;
84
85
86 private final static byte IP_V4 = 1,
87 DMNAME = 3,
88 IP_V6 = 4;
89
90
91
92
93
94
95
96
97
98
99
100
101 SocksClient(String host, int port)
102 {
103 this.socks_host = host;
104 this.socks_port = port;
105 this.socks_version = -1;
106 }
107
108
109
110
111
112
113
114
115
116
117
118 SocksClient(String host, int port, int version) throws SocksException
119 {
120 this.socks_host = host;
121 this.socks_port = port;
122
123 if (version != 4 && version != 5)
124 throw new SocksException("SOCKS Version not supported: "+version);
125 this.socks_version = version;
126 }
127
128
129
130
131
132
133
134
135
136
137
138
139
140 Socket getSocket(String host, int port) throws IOException
141 {
142 return getSocket(host, port, null, -1);
143 }
144
145
146
147
148
149
150
151
152
153
154
155
156 Socket getSocket(String host, int port, InetAddress localAddr,
157 int localPort) throws IOException
158 {
159 Socket sock = null;
160
161 try
162 {
163 Log.write(Log.SOCKS, "Socks: contacting server on " +
164 socks_host + ":" + socks_port);
165
166
167
168
169 sock = connect(socks_host, socks_port, localAddr, localPort);
170 InputStream inp = sock.getInputStream();
171 OutputStream out = sock.getOutputStream();
172
173
174
175
176 switch (socks_version)
177 {
178 case 4:
179 v4ProtExchg(inp, out, host, port);
180 break;
181 case 5:
182 v5ProtExchg(inp, out, host, port);
183 break;
184 case -1:
185
186 try
187 {
188 v4ProtExchg(inp, out, host, port);
189 socks_version = 4;
190 }
191 catch (SocksException se)
192 {
193 Log.write(Log.SOCKS, "Socks: V4 request failed: " +
194 se.getMessage());
195
196 sock.close();
197 sock = connect(socks_host, socks_port, localAddr,
198 localPort);
199 inp = sock.getInputStream();
200 out = sock.getOutputStream();
201
202 v5ProtExchg(inp, out, host, port);
203 socks_version = 5;
204 }
205 break;
206 default:
207 throw new Error("SocksClient internal error: unknown " +
208 "version "+socks_version);
209 }
210
211 Log.write(Log.SOCKS, "Socks: connection established.");
212
213 return sock;
214 }
215 catch (IOException ioe)
216 {
217 if (sock != null)
218 {
219 try { sock.close(); }
220 catch (IOException ee) {}
221 }
222
223 throw ioe;
224 }
225 }
226
227
228
229
230
231
232
233
234
235
236
237
238
239 private static final Socket connect(String host, int port,
240 InetAddress localAddr, int localPort)
241 throws IOException
242 {
243 InetAddress[] addr_list = InetAddress.getAllByName(host);
244 for (int idx=0; idx<addr_list.length; idx++)
245 {
246 try
247 {
248 if (localAddr == null)
249 return new Socket(addr_list[idx], port);
250 else
251 return new Socket(addr_list[idx], port, localAddr, localPort);
252 }
253 catch (SocketException se)
254 {
255 if (idx < addr_list.length-1)
256 continue;
257 else
258 throw se;
259 }
260 }
261
262 return null;
263 }
264
265
266 private boolean v4A = false;
267 private byte[] user = null;
268
269
270
271
272 private void v4ProtExchg(InputStream inp, OutputStream out, String host,
273 int port)
274 throws SocksException, IOException
275 {
276 ByteArrayOutputStream buffer = new ByteArrayOutputStream(100);
277
278 Log.write(Log.SOCKS, "Socks: Beginning V4 Protocol Exchange for host "
279 + host + ":" + port);
280
281
282
283 byte[] addr = { 0, 0, 0, 42 };
284 if (!v4A)
285 {
286 try
287 { addr = InetAddress.getByName(host).getAddress(); }
288
289 catch (UnknownHostException uhe)
290 { v4A = true; }
291 catch (SecurityException se)
292 { v4A = true; }
293 if (v4A)
294 Log.write(Log.SOCKS, "Socks: Switching to version 4A");
295 }
296
297 if (user == null)
298 {
299 String user_str;
300 try
301 { user_str = System.getProperty("user.name", ""); }
302 catch (SecurityException se)
303 { user_str = "";
304 byte[] tmp = user_str.getBytes();
305 user = new byte[tmp.length+1];
306 System.arraycopy(tmp, 0, user, 0, tmp.length);
307 user[user_str.length()] = 0;
308 }
309
310
311
312
313 Log.write(Log.SOCKS, "Socks: Sending connect request for user " +
314 new String(user, 0, user.length-1));
315
316 buffer.reset();
317 buffer.write(4);
318 buffer.write(CONNECT);
319 buffer.write((port >> 8) & 0xff);
320 buffer.write(port & 0xff);
321 buffer.write(addr);
322 buffer.write(user);
323 if (v4A)
324 {
325 buffer.write(host.getBytes("8859_1"));
326 buffer.write(0);
327 }
328 buffer.writeTo(out);
329
330
331
332
333 int version = inp.read();
334 if (version == -1)
335 throw new SocksException("Connection refused by server");
336 else if (version == 4)
337 Log.write(Log.SOCKS, "Socks: Warning: received version 4 " +
338 "instead of 0");
339 else if (version != 0)
340 throw new SocksException("Received invalid version: " + version +
341 "; expected: 0");
342
343 int sts = inp.read();
344
345 Log.write(Log.SOCKS, "Socks: Received response; version: " + version +
346 "; status: " + sts);
347
348 switch (sts)
349 {
350 case 90:
351 break;
352 case 91:
353 throw new SocksException("Connection request rejected");
354 case 92:
355 throw new SocksException("Connection request rejected: " +
356 "can't connect to identd");
357 case 93:
358 throw new SocksException("Connection request rejected: " +
359 "identd reports different user-id " +
360 "from "+
361 new String(user, 0, user.length-1));
362 default:
363 throw new SocksException("Connection request rejected: " +
364 "unknown error " + sts);
365 }
366
367 byte[] skip = new byte[2+4];
368 int rcvd = 0,
369 tot = 0;
370 while (tot < skip.length &&
371 (rcvd = inp.read(skip, 0, skip.length-tot)) != -1)
372 tot += rcvd;
373 }
374
375
376
377
378
379
380 private void v5ProtExchg(InputStream inp, OutputStream out, String host,
381 int port)
382 throws SocksException, IOException
383 {
384 int version;
385 ByteArrayOutputStream buffer = new ByteArrayOutputStream(100);
386
387 Log.write(Log.SOCKS, "Socks: Beginning V5 Protocol Exchange for host "
388 + host + ":" + port);
389
390
391
392 Log.write(Log.SOCKS, "Socks: Sending authentication request; methods"
393 + " No-Authentication, Username/Password");
394
395 buffer.reset();
396 buffer.write(5);
397 buffer.write(2);
398 buffer.write(NO_AUTH);
399 buffer.write(USERPWD);
400
401 buffer.writeTo(out);
402
403
404
405
406 version = inp.read();
407 if (version == -1)
408 throw new SocksException("Connection refused by server");
409 else if (version != 5)
410 throw new SocksException("Received invalid version: " + version +
411 "; expected: 5");
412
413 int method = inp.read();
414
415 Log.write(Log.SOCKS, "Socks: Received response; version: " + version +
416 "; method: " + method);
417
418
419
420
421 switch(method)
422 {
423 case NO_AUTH:
424 break;
425 case GSSAPI:
426 negotiate_gssapi(inp, out);
427 break;
428 case USERPWD:
429 negotiate_userpwd(inp, out);
430 break;
431 case NO_ACC:
432 throw new SocksException("Server unwilling to accept any " +
433 "standard authentication methods");
434 default:
435 throw new SocksException("Cannot handle authentication method "
436 + method);
437 }
438
439
440
441
442 Log.write(Log.SOCKS, "Socks: Sending connect request");
443
444 buffer.reset();
445 buffer.write(5);
446 buffer.write(CONNECT);
447 buffer.write(0);
448 buffer.write(DMNAME);
449 buffer.write(host.length() & 0xff);
450 buffer.write(host.getBytes("8859_1"));
451 buffer.write((port >> 8) & 0xff);
452 buffer.write(port & 0xff);
453 buffer.writeTo(out);
454
455
456
457
458 version = inp.read();
459 if (version != 5)
460 throw new SocksException("Received invalid version: " + version +
461 "; expected: 5");
462
463 int sts = inp.read();
464
465 Log.write(Log.SOCKS, "Socks: Received response; version: " + version +
466 "; status: " + sts);
467
468 switch (sts)
469 {
470 case 0:
471 break;
472 case 1:
473 throw new SocksException("General SOCKS server failure");
474 case 2:
475 throw new SocksException("Connection not allowed");
476 case 3:
477 throw new SocksException("Network unreachable");
478 case 4:
479 throw new SocksException("Host unreachable");
480 case 5:
481 throw new SocksException("Connection refused");
482 case 6:
483 throw new SocksException("TTL expired");
484 case 7:
485 throw new SocksException("Command not supported");
486 case 8:
487 throw new SocksException("Address type not supported");
488 default:
489 throw new SocksException("Unknown reply received from server: "
490 + sts);
491 }
492
493 inp.read();
494 int atype = inp.read(),
495 alen;
496 switch(atype)
497 {
498 case IP_V6:
499 alen = 16;
500 break;
501 case IP_V4:
502 alen = 4;
503 break;
504 case DMNAME:
505 alen = inp.read();
506 break;
507 default:
508 throw new SocksException("Invalid address type received from" +
509 " server: "+atype);
510 }
511
512 byte[] skip = new byte[alen+2];
513 int rcvd = 0,
514 tot = 0;
515 while (tot < skip.length &&
516 (rcvd = inp.read(skip, 0, skip.length-tot)) != -1)
517 tot += rcvd;
518 }
519
520
521
522
523
524
525
526
527
528 private void negotiate_gssapi(InputStream inp, OutputStream out)
529 throws SocksException, IOException
530 {
531 throw new
532 SocksException("GSSAPI authentication protocol not implemented");
533 }
534
535
536
537
538
539
540
541
542
543
544
545 private void negotiate_userpwd(InputStream inp, OutputStream out)
546 throws SocksException, IOException
547 {
548 byte[] buffer;
549
550
551 Log.write(Log.SOCKS, "Socks: Entering authorization subnegotiation" +
552 "; method: Username/Password");
553
554
555
556 AuthorizationInfo auth_info;
557 try
558 {
559 auth_info =
560 AuthorizationInfo.getAuthorization(socks_host, socks_port,
561 "SOCKS5", "USER/PASS",
562 null, null, true);
563 }
564 catch (AuthSchemeNotImplException atnie)
565 { auth_info = null; }
566
567 if (auth_info == null)
568 throw new SocksException("No Authorization info for SOCKS found " +
569 "(server requested username/password).");
570
571 NVPair[] unpw = auth_info.getParams();
572 if (unpw == null || unpw.length == 0)
573 throw new SocksException("No Username/Password found in " +
574 "authorization info for SOCKS.");
575
576 String user_str = unpw[0].getName();
577 String pass_str = unpw[0].getValue();
578
579
580
581
582 Log.write(Log.SOCKS, "Socks: Sending authorization request for user "+
583 user_str);
584
585 byte[] utmp = user_str.getBytes();
586 byte[] ptmp = pass_str.getBytes();
587 buffer = new byte[1+1+utmp.length+1+ptmp.length];
588 buffer[0] = 1;
589 buffer[1] = (byte) utmp.length;
590 System.arraycopy(utmp, 0, buffer, 2, utmp.length);
591 buffer[2+buffer[1]] = (byte) ptmp.length;
592 System.arraycopy(ptmp, 0, buffer, 2+buffer[1]+1, ptmp.length);
593 out.write(buffer);
594
595
596
597
598 int version = inp.read();
599 if (version != 1)
600 throw new SocksException("Wrong version received in username/" +
601 "password subnegotiation response: " +
602 version + "; expected: 1");
603
604 int sts = inp.read();
605 if (sts != 0)
606 throw new SocksException("Username/Password authentication " +
607 "failed; status: "+sts);
608
609 Log.write(Log.SOCKS, "Socks: Received response; version: " + version +
610 "; status: " + sts);
611 }
612
613
614
615
616
617
618 public String toString()
619 {
620 return getClass().getName() + "[" + socks_host + ":" + socks_port + "]";
621 }
622 }