History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/net/SocksSocketImpl.java (1 of 18352 files). Show all

Unified · Split

java/pkg/java/net/SocksSocketImpl.java+1085−0
@@ -0,0 +1,1085 @@
1/*
2 * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25package java.net;
26import java.io.IOException;
27import java.io.InputStream;
28import java.io.OutputStream;
29import java.io.BufferedOutputStream;
30import java.security.AccessController;
31import java.security.PrivilegedExceptionAction;
32import sun.net.SocksProxy;
33import sun.net.www.ParseUtil;
34/* import org.ietf.jgss.*; */
35
36/**
37 * SOCKS (V4 & V5) TCP socket implementation (RFC 1928).
38 * This is a subclass of PlainSocketImpl.
39 * Note this class should <b>NOT</b> be public.
40 */
41
42class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
43 private String server = null;
44 private int serverPort = DEFAULT_PORT;
45 private InetSocketAddress external_address;
46 private boolean useV4 = false;
47 private Socket cmdsock = null;
48 private InputStream cmdIn = null;
49 private OutputStream cmdOut = null;
50 /* true if the Proxy has been set programatically */
51 private boolean applicationSetProxy; /* false */
52
53
54 SocksSocketImpl() {
55 // Nothing needed
56 }
57
58 SocksSocketImpl(String server, int port) {
59 this.server = server;
60 this.serverPort = (port == -1 ? DEFAULT_PORT : port);
61 }
62
63 SocksSocketImpl(Proxy proxy) {
64 SocketAddress a = proxy.address();
65 if (a instanceof InetSocketAddress) {
66 InetSocketAddress ad = (InetSocketAddress) a;
67 // Use getHostString() to avoid reverse lookups
68 server = ad.getHostString();
69 serverPort = ad.getPort();
70 }
71 }
72
73 void setV4() {
74 useV4 = true;
75 }
76
77 private synchronized void privilegedConnect(final String host,
78 final int port,
79 final int timeout)
80 throws IOException
81 {
82 try {
83 AccessController.doPrivileged(
84 new java.security.PrivilegedExceptionAction<Void>() {
85 public Void run() throws IOException {
86 superConnectServer(host, port, timeout);
87 cmdIn = getInputStream();
88 cmdOut = getOutputStream();
89 return null;
90 }
91 });
92 } catch (java.security.PrivilegedActionException pae) {
93 throw (IOException) pae.getException();
94 }
95 }
96
97 private void superConnectServer(String host, int port,
98 int timeout) throws IOException {
99 super.connect(new InetSocketAddress(host, port), timeout);
100 }
101
102 private static int remainingMillis(long deadlineMillis) throws IOException {
103 if (deadlineMillis == 0L)
104 return 0;
105
106 final long remaining = deadlineMillis - System.currentTimeMillis();
107 if (remaining > 0)
108 return (int) remaining;
109
110 throw new SocketTimeoutException();
111 }
112
113 private int readSocksReply(InputStream in, byte[] data) throws IOException {
114 return readSocksReply(in, data, 0L);
115 }
116
117 private int readSocksReply(InputStream in, byte[] data, long deadlineMillis) throws IOException {
118 int len = data.length;
119 int received = 0;
120 for (int attempts = 0; received < len && attempts < 3; attempts++) {
121 int count;
122 try {
123 count = ((SocketInputStream)in).read(data, received, len - received, remainingMillis(deadlineMillis));
124 } catch (SocketTimeoutException e) {
125 throw new SocketTimeoutException("Connect timed out");
126 }
127 if (count < 0)
128 throw new SocketException("Malformed reply from SOCKS server");
129 received += count;
130 }
131 return received;
132 }
133
134 /**
135 * Provides the authentication machanism required by the proxy.
136 */
137 private boolean authenticate(byte method, InputStream in,
138 BufferedOutputStream out) throws IOException {
139 return authenticate(method, in, out, 0L);
140 }
141
142 private boolean authenticate(byte method, InputStream in,
143 BufferedOutputStream out,
144 long deadlineMillis) throws IOException {
145 // No Authentication required. We're done then!
146 if (method == NO_AUTH)
147 return true;
148 /**
149 * User/Password authentication. Try, in that order :
150 * - The application provided Authenticator, if any
151 * - the user.name & no password (backward compatibility behavior).
152 */
153 if (method == USER_PASSW) {
154 String userName;
155 String password = null;
156 final InetAddress addr = InetAddress.getByName(server);
157 PasswordAuthentication pw =
158 java.security.AccessController.doPrivileged(
159 new java.security.PrivilegedAction<PasswordAuthentication>() {
160 public PasswordAuthentication run() {
161 return Authenticator.requestPasswordAuthentication(
162 server, addr, serverPort, "SOCKS5", "SOCKS authentication", null);
163 }
164 });
165 if (pw != null) {
166 userName = pw.getUserName();
167 password = new String(pw.getPassword());
168 } else {
169 userName = java.security.AccessController.doPrivileged(
170 new sun.security.action.GetPropertyAction("user.name"));
171 }
172 if (userName == null)
173 return false;
174 out.write(1);
175 out.write(userName.length());
176 try {
177 out.write(userName.getBytes("ISO-8859-1"));
178 } catch (java.io.UnsupportedEncodingException uee) {
179 assert false;
180 }
181 if (password != null) {
182 out.write(password.length());
183 try {
184 out.write(password.getBytes("ISO-8859-1"));
185 } catch (java.io.UnsupportedEncodingException uee) {
186 assert false;
187 }
188 } else
189 out.write(0);
190 out.flush();
191 byte[] data = new byte[2];
192 int i = readSocksReply(in, data, deadlineMillis);
193 if (i != 2 || data[1] != 0) {
194 /* RFC 1929 specifies that the connection MUST be closed if
195 authentication fails */
196 out.close();
197 in.close();
198 return false;
199 }
200 /* Authentication succeeded */
201 return true;
202 }
203 /**
204 * GSSAPI authentication mechanism.
205 * Unfortunately the RFC seems out of sync with the Reference
206 * implementation. I'll leave this in for future completion.
207 */
208// if (method == GSSAPI) {
209// try {
210// GSSManager manager = GSSManager.getInstance();
211// GSSName name = manager.createName("SERVICE:socks@"+server,
212// null);
213// GSSContext context = manager.createContext(name, null, null,
214// GSSContext.DEFAULT_LIFETIME);
215// context.requestMutualAuth(true);
216// context.requestReplayDet(true);
217// context.requestSequenceDet(true);
218// context.requestCredDeleg(true);
219// byte []inToken = new byte[0];
220// while (!context.isEstablished()) {
221// byte[] outToken
222// = context.initSecContext(inToken, 0, inToken.length);
223// // send the output token if generated
224// if (outToken != null) {
225// out.write(1);
226// out.write(1);
227// out.writeShort(outToken.length);
228// out.write(outToken);
229// out.flush();
230// data = new byte[2];
231// i = readSocksReply(in, data, deadlineMillis);
232// if (i != 2 || data[1] == 0xff) {
233// in.close();
234// out.close();
235// return false;
236// }
237// i = readSocksReply(in, data, deadlineMillis);
238// int len = 0;
239// len = ((int)data[0] & 0xff) << 8;
240// len += data[1];
241// data = new byte[len];
242// i = readSocksReply(in, data, deadlineMillis);
243// if (i == len)
244// return true;
245// in.close();
246// out.close();
247// }
248// }
249// } catch (GSSException e) {
250// /* RFC 1961 states that if Context initialisation fails the connection
251// MUST be closed */
252// e.printStackTrace();
253// in.close();
254// out.close();
255// }
256// }
257 return false;
258 }
259
260 private void connectV4(InputStream in, OutputStream out,
261 InetSocketAddress endpoint,
262 long deadlineMillis) throws IOException {
263 if (!(endpoint.getAddress() instanceof Inet4Address)) {
264 throw new SocketException("SOCKS V4 requires IPv4 only addresses");
265 }
266 out.write(PROTO_VERS4);
267 out.write(CONNECT);
268 out.write((endpoint.getPort() >> 8) & 0xff);
269 out.write((endpoint.getPort() >> 0) & 0xff);
270 out.write(endpoint.getAddress().getAddress());
271 String userName = getUserName();
272 try {
273 out.write(userName.getBytes("ISO-8859-1"));
274 } catch (java.io.UnsupportedEncodingException uee) {
275 assert false;
276 }
277 out.write(0);
278 out.flush();
279 byte[] data = new byte[8];
280 int n = readSocksReply(in, data, deadlineMillis);
281 if (n != 8)
282 throw new SocketException("Reply from SOCKS server has bad length: " + n);
283 if (data[0] != 0 && data[0] != 4)
284 throw new SocketException("Reply from SOCKS server has bad version");
285 SocketException ex = null;
286 switch (data[1]) {
287 case 90:
288 // Success!
289 external_address = endpoint;
290 break;
291 case 91:
292 ex = new SocketException("SOCKS request rejected");
293 break;
294 case 92:
295 ex = new SocketException("SOCKS server couldn't reach destination");
296 break;
297 case 93:
298 ex = new SocketException("SOCKS authentication failed");
299 break;
300 default:
301 ex = new SocketException("Reply from SOCKS server contains bad status");
302 break;
303 }
304 if (ex != null) {
305 in.close();
306 out.close();
307 throw ex;
308 }
309 }
310
311 /**
312 * Connects the Socks Socket to the specified endpoint. It will first
313 * connect to the SOCKS proxy and negotiate the access. If the proxy
314 * grants the connections, then the connect is successful and all
315 * further traffic will go to the "real" endpoint.
316 *
317 * @param endpoint the <code>SocketAddress</code> to connect to.
318 * @param timeout the timeout value in milliseconds
319 * @throws IOException if the connection can't be established.
320 * @throws SecurityException if there is a security manager and it
321 * doesn't allow the connection
322 * @throws IllegalArgumentException if endpoint is null or a
323 * SocketAddress subclass not supported by this socket
324 */
325 @Override
326 protected void connect(SocketAddress endpoint, int timeout) throws IOException {
327 final long deadlineMillis;
328
329 if (timeout == 0) {
330 deadlineMillis = 0L;
331 } else {
332 long finish = System.currentTimeMillis() + timeout;
333 deadlineMillis = finish < 0 ? Long.MAX_VALUE : finish;
334 }
335
336 SecurityManager security = System.getSecurityManager();
337 if (endpoint == null || !(endpoint instanceof InetSocketAddress))
338 throw new IllegalArgumentException("Unsupported address type");
339 InetSocketAddress epoint = (InetSocketAddress) endpoint;
340 if (security != null) {
341 if (epoint.isUnresolved())
342 security.checkConnect(epoint.getHostName(),
343 epoint.getPort());
344 else
345 security.checkConnect(epoint.getAddress().getHostAddress(),
346 epoint.getPort());
347 }
348 if (server == null) {
349 // This is the general case
350 // server is not null only when the socket was created with a
351 // specified proxy in which case it does bypass the ProxySelector
352 ProxySelector sel = java.security.AccessController.doPrivileged(
353 new java.security.PrivilegedAction<ProxySelector>() {
354 public ProxySelector run() {
355 return ProxySelector.getDefault();
356 }
357 });
358 if (sel == null) {
359 /*
360 * No default proxySelector --> direct connection
361 */
362 super.connect(epoint, remainingMillis(deadlineMillis));
363 return;
364 }
365 URI uri;
366 // Use getHostString() to avoid reverse lookups
367 String host = epoint.getHostString();
368 // IPv6 litteral?
369 if (epoint.getAddress() instanceof Inet6Address &&
370 (!host.startsWith("[")) && (host.indexOf(":") >= 0)) {
371 host = "[" + host + "]";
372 }
373 try {
374 uri = new URI("socket://" + ParseUtil.encodePath(host) + ":"+ epoint.getPort());
375 } catch (URISyntaxException e) {
376 // This shouldn't happen
377 assert false : e;
378 uri = null;
379 }
380 Proxy p = null;
381 IOException savedExc = null;
382 java.util.Iterator<Proxy> iProxy = null;
383 iProxy = sel.select(uri).iterator();
384 if (iProxy == null || !(iProxy.hasNext())) {
385 super.connect(epoint, remainingMillis(deadlineMillis));
386 return;
387 }
388 while (iProxy.hasNext()) {
389 p = iProxy.next();
390 if (p == null || p == Proxy.NO_PROXY) {
391 super.connect(epoint, remainingMillis(deadlineMillis));
392 return;
393 }
394 if (p.type() != Proxy.Type.SOCKS)
395 throw new SocketException("Unknown proxy type : " + p.type());
396 if (!(p.address() instanceof InetSocketAddress))
397 throw new SocketException("Unknow address type for proxy: " + p);
398 // Use getHostString() to avoid reverse lookups
399 server = ((InetSocketAddress) p.address()).getHostString();
400 serverPort = ((InetSocketAddress) p.address()).getPort();
401 if (p instanceof SocksProxy) {
402 if (((SocksProxy)p).protocolVersion() == 4) {
403 useV4 = true;
404 }
405 }
406
407 // Connects to the SOCKS server
408 try {
409 privilegedConnect(server, serverPort, remainingMillis(deadlineMillis));
410 // Worked, let's get outta here
411 break;
412 } catch (IOException e) {
413 // Ooops, let's notify the ProxySelector
414 sel.connectFailed(uri,p.address(),e);
415 server = null;
416 serverPort = -1;
417 savedExc = e;
418 // Will continue the while loop and try the next proxy
419 }
420 }
421
422 /*
423 * If server is still null at this point, none of the proxy
424 * worked
425 */
426 if (server == null) {
427 throw new SocketException("Can't connect to SOCKS proxy:"
428 + savedExc.getMessage());
429 }
430 } else {
431 // Connects to the SOCKS server
432 try {
433 privilegedConnect(server, serverPort, remainingMillis(deadlineMillis));
434 } catch (IOException e) {
435 throw new SocketException(e.getMessage());
436 }
437 }
438
439 // cmdIn & cmdOut were intialized during the privilegedConnect() call
440 BufferedOutputStream out = new BufferedOutputStream(cmdOut, 512);
441 InputStream in = cmdIn;
442
443 if (useV4) {
444 // SOCKS Protocol version 4 doesn't know how to deal with
445 // DOMAIN type of addresses (unresolved addresses here)
446 if (epoint.isUnresolved())
447 throw new UnknownHostException(epoint.toString());
448 connectV4(in, out, epoint, deadlineMillis);
449 return;
450 }
451
452 // This is SOCKS V5
453 out.write(PROTO_VERS);
454 out.write(2);
455 out.write(NO_AUTH);
456 out.write(USER_PASSW);
457 out.flush();
458 byte[] data = new byte[2];
459 int i = readSocksReply(in, data, deadlineMillis);
460 if (i != 2 || ((int)data[0]) != PROTO_VERS) {
461 // Maybe it's not a V5 sever after all
462 // Let's try V4 before we give up
463 // SOCKS Protocol version 4 doesn't know how to deal with
464 // DOMAIN type of addresses (unresolved addresses here)
465 if (epoint.isUnresolved())
466 throw new UnknownHostException(epoint.toString());
467 connectV4(in, out, epoint, deadlineMillis);
468 return;
469 }
470 if (((int)data[1]) == NO_METHODS)
471 throw new SocketException("SOCKS : No acceptable methods");
472 if (!authenticate(data[1], in, out, deadlineMillis)) {
473 throw new SocketException("SOCKS : authentication failed");
474 }
475 out.write(PROTO_VERS);
476 out.write(CONNECT);
477 out.write(0);
478 /* Test for IPV4/IPV6/Unresolved */
479 if (epoint.isUnresolved()) {
480 out.write(DOMAIN_NAME);
481 out.write(epoint.getHostName().length());
482 try {
483 out.write(epoint.getHostName().getBytes("ISO-8859-1"));
484 } catch (java.io.UnsupportedEncodingException uee) {
485 assert false;
486 }
487 out.write((epoint.getPort() >> 8) & 0xff);
488 out.write((epoint.getPort() >> 0) & 0xff);
489 } else if (epoint.getAddress() instanceof Inet6Address) {
490 out.write(IPV6);
491 out.write(epoint.getAddress().getAddress());
492 out.write((epoint.getPort() >> 8) & 0xff);
493 out.write((epoint.getPort() >> 0) & 0xff);
494 } else {
495 out.write(IPV4);
496 out.write(epoint.getAddress().getAddress());
497 out.write((epoint.getPort() >> 8) & 0xff);
498 out.write((epoint.getPort() >> 0) & 0xff);
499 }
500 out.flush();
501 data = new byte[4];
502 i = readSocksReply(in, data, deadlineMillis);
503 if (i != 4)
504 throw new SocketException("Reply from SOCKS server has bad length");
505 SocketException ex = null;
506 int len;
507 byte[] addr;
508 switch (data[1]) {
509 case REQUEST_OK:
510 // success!
511 switch(data[3]) {
512 case IPV4:
513 addr = new byte[4];
514 i = readSocksReply(in, addr, deadlineMillis);
515 if (i != 4)
516 throw new SocketException("Reply from SOCKS server badly formatted");
517 data = new byte[2];
518 i = readSocksReply(in, data, deadlineMillis);
519 if (i != 2)
520 throw new SocketException("Reply from SOCKS server badly formatted");
521 break;
522 case DOMAIN_NAME:
523 len = data[1];
524 byte[] host = new byte[len];
525 i = readSocksReply(in, host, deadlineMillis);
526 if (i != len)
527 throw new SocketException("Reply from SOCKS server badly formatted");
528 data = new byte[2];
529 i = readSocksReply(in, data, deadlineMillis);
530 if (i != 2)
531 throw new SocketException("Reply from SOCKS server badly formatted");
532 break;
533 case IPV6:
534 len = data[1];
535 addr = new byte[len];
536 i = readSocksReply(in, addr, deadlineMillis);
537 if (i != len)
538 throw new SocketException("Reply from SOCKS server badly formatted");
539 data = new byte[2];
540 i = readSocksReply(in, data, deadlineMillis);
541 if (i != 2)
542 throw new SocketException("Reply from SOCKS server badly formatted");
543 break;
544 default:
545 ex = new SocketException("Reply from SOCKS server contains wrong code");
546 break;
547 }
548 break;
549 case GENERAL_FAILURE:
550 ex = new SocketException("SOCKS server general failure");
551 break;
552 case NOT_ALLOWED:
553 ex = new SocketException("SOCKS: Connection not allowed by ruleset");
554 break;
555 case NET_UNREACHABLE:
556 ex = new SocketException("SOCKS: Network unreachable");
557 break;
558 case HOST_UNREACHABLE:
559 ex = new SocketException("SOCKS: Host unreachable");
560 break;
561 case CONN_REFUSED:
562 ex = new SocketException("SOCKS: Connection refused");
563 break;
564 case TTL_EXPIRED:
565 ex = new SocketException("SOCKS: TTL expired");
566 break;
567 case CMD_NOT_SUPPORTED:
568 ex = new SocketException("SOCKS: Command not supported");
569 break;
570 case ADDR_TYPE_NOT_SUP:
571 ex = new SocketException("SOCKS: address type not supported");
572 break;
573 }
574 if (ex != null) {
575 in.close();
576 out.close();
577 throw ex;
578 }
579 external_address = epoint;
580 }
581
582 private void bindV4(InputStream in, OutputStream out,
583 InetAddress baddr,
584 int lport) throws IOException {
585 if (!(baddr instanceof Inet4Address)) {
586 throw new SocketException("SOCKS V4 requires IPv4 only addresses");
587 }
588 super.bind(baddr, lport);
589 byte[] addr1 = baddr.getAddress();
590 /* Test for AnyLocal */
591 InetAddress naddr = baddr;
592 if (naddr.isAnyLocalAddress()) {
593 naddr = cmdsock.getLocalAddress();
594 addr1 = naddr.getAddress();
595 }
596 out.write(PROTO_VERS4);
597 out.write(BIND);
598 out.write((super.getLocalPort() >> 8) & 0xff);
599 out.write((super.getLocalPort() >> 0) & 0xff);
600 out.write(addr1);
601 String userName = getUserName();
602 try {
603 out.write(userName.getBytes("ISO-8859-1"));
604 } catch (java.io.UnsupportedEncodingException uee) {
605 assert false;
606 }
607 out.write(0);
608 out.flush();
609 byte[] data = new byte[8];
610 int n = readSocksReply(in, data);
611 if (n != 8)
612 throw new SocketException("Reply from SOCKS server has bad length: " + n);
613 if (data[0] != 0 && data[0] != 4)
614 throw new SocketException("Reply from SOCKS server has bad version");
615 SocketException ex = null;
616 switch (data[1]) {
617 case 90:
618 // Success!
619 external_address = new InetSocketAddress(baddr, lport);
620 break;
621 case 91:
622 ex = new SocketException("SOCKS request rejected");
623 break;
624 case 92:
625 ex = new SocketException("SOCKS server couldn't reach destination");
626 break;
627 case 93:
628 ex = new SocketException("SOCKS authentication failed");
629 break;
630 default:
631 ex = new SocketException("Reply from SOCKS server contains bad status");
632 break;
633 }
634 if (ex != null) {
635 in.close();
636 out.close();
637 throw ex;
638 }
639
640 }
641
642 /**
643 * Sends the Bind request to the SOCKS proxy. In the SOCKS protocol, bind
644 * means "accept incoming connection from", so the SocketAddress is the
645 * the one of the host we do accept connection from.
646 *
647 * @param addr the Socket address of the remote host.
648 * @exception IOException if an I/O error occurs when binding this socket.
649 */
650 protected synchronized void socksBind(InetSocketAddress saddr) throws IOException {
651 if (socket != null) {
652 // this is a client socket, not a server socket, don't
653 // call the SOCKS proxy for a bind!
654 return;
655 }
656
657 // Connects to the SOCKS server
658
659 if (server == null) {
660 // This is the general case
661 // server is not null only when the socket was created with a
662 // specified proxy in which case it does bypass the ProxySelector
663 ProxySelector sel = java.security.AccessController.doPrivileged(
664 new java.security.PrivilegedAction<ProxySelector>() {
665 public ProxySelector run() {
666 return ProxySelector.getDefault();
667 }
668 });
669 if (sel == null) {
670 /*
671 * No default proxySelector --> direct connection
672 */
673 return;
674 }
675 URI uri;
676 // Use getHostString() to avoid reverse lookups
677 String host = saddr.getHostString();
678 // IPv6 litteral?
679 if (saddr.getAddress() instanceof Inet6Address &&
680 (!host.startsWith("[")) && (host.indexOf(":") >= 0)) {
681 host = "[" + host + "]";
682 }
683 try {
684 uri = new URI("serversocket://" + ParseUtil.encodePath(host) + ":"+ saddr.getPort());
685 } catch (URISyntaxException e) {
686 // This shouldn't happen
687 assert false : e;
688 uri = null;
689 }
690 Proxy p = null;
691 Exception savedExc = null;
692 java.util.Iterator<Proxy> iProxy = null;
693 iProxy = sel.select(uri).iterator();
694 if (iProxy == null || !(iProxy.hasNext())) {
695 return;
696 }
697 while (iProxy.hasNext()) {
698 p = iProxy.next();
699 if (p == null || p == Proxy.NO_PROXY) {
700 return;
701 }
702 if (p.type() != Proxy.Type.SOCKS)
703 throw new SocketException("Unknown proxy type : " + p.type());
704 if (!(p.address() instanceof InetSocketAddress))
705 throw new SocketException("Unknow address type for proxy: " + p);
706 // Use getHostString() to avoid reverse lookups
707 server = ((InetSocketAddress) p.address()).getHostString();
708 serverPort = ((InetSocketAddress) p.address()).getPort();
709 if (p instanceof SocksProxy) {
710 if (((SocksProxy)p).protocolVersion() == 4) {
711 useV4 = true;
712 }
713 }
714
715 // Connects to the SOCKS server
716 try {
717 AccessController.doPrivileged(
718 new PrivilegedExceptionAction<Void>() {
719 public Void run() throws Exception {
720 cmdsock = new Socket(new PlainSocketImpl());
721 cmdsock.connect(new InetSocketAddress(server, serverPort));
722 cmdIn = cmdsock.getInputStream();
723 cmdOut = cmdsock.getOutputStream();
724 return null;
725 }
726 });
727 } catch (Exception e) {
728 // Ooops, let's notify the ProxySelector
729 sel.connectFailed(uri,p.address(),new SocketException(e.getMessage()));
730 server = null;
731 serverPort = -1;
732 cmdsock = null;
733 savedExc = e;
734 // Will continue the while loop and try the next proxy
735 }
736 }
737
738 /*
739 * If server is still null at this point, none of the proxy
740 * worked
741 */
742 if (server == null || cmdsock == null) {
743 throw new SocketException("Can't connect to SOCKS proxy:"
744 + savedExc.getMessage());
745 }
746 } else {
747 try {
748 AccessController.doPrivileged(
749 new PrivilegedExceptionAction<Void>() {
750 public Void run() throws Exception {
751 cmdsock = new Socket(new PlainSocketImpl());
752 cmdsock.connect(new InetSocketAddress(server, serverPort));
753 cmdIn = cmdsock.getInputStream();
754 cmdOut = cmdsock.getOutputStream();
755 return null;
756 }
757 });
758 } catch (Exception e) {
759 throw new SocketException(e.getMessage());
760 }
761 }
762 BufferedOutputStream out = new BufferedOutputStream(cmdOut, 512);
763 InputStream in = cmdIn;
764 if (useV4) {
765 bindV4(in, out, saddr.getAddress(), saddr.getPort());
766 return;
767 }
768 out.write(PROTO_VERS);
769 out.write(2);
770 out.write(NO_AUTH);
771 out.write(USER_PASSW);
772 out.flush();
773 byte[] data = new byte[2];
774 int i = readSocksReply(in, data);
775 if (i != 2 || ((int)data[0]) != PROTO_VERS) {
776 // Maybe it's not a V5 sever after all
777 // Let's try V4 before we give up
778 bindV4(in, out, saddr.getAddress(), saddr.getPort());
779 return;
780 }
781 if (((int)data[1]) == NO_METHODS)
782 throw new SocketException("SOCKS : No acceptable methods");
783 if (!authenticate(data[1], in, out)) {
784 throw new SocketException("SOCKS : authentication failed");
785 }
786 // We're OK. Let's issue the BIND command.
787 out.write(PROTO_VERS);
788 out.write(BIND);
789 out.write(0);
790 int lport = saddr.getPort();
791 if (saddr.isUnresolved()) {
792 out.write(DOMAIN_NAME);
793 out.write(saddr.getHostName().length());
794 try {
795 out.write(saddr.getHostName().getBytes("ISO-8859-1"));
796 } catch (java.io.UnsupportedEncodingException uee) {
797 assert false;
798 }
799 out.write((lport >> 8) & 0xff);
800 out.write((lport >> 0) & 0xff);
801 } else if (saddr.getAddress() instanceof Inet4Address) {
802 byte[] addr1 = saddr.getAddress().getAddress();
803 out.write(IPV4);
804 out.write(addr1);
805 out.write((lport >> 8) & 0xff);
806 out.write((lport >> 0) & 0xff);
807 out.flush();
808 } else if (saddr.getAddress() instanceof Inet6Address) {
809 byte[] addr1 = saddr.getAddress().getAddress();
810 out.write(IPV6);
811 out.write(addr1);
812 out.write((lport >> 8) & 0xff);
813 out.write((lport >> 0) & 0xff);
814 out.flush();
815 } else {
816 cmdsock.close();
817 throw new SocketException("unsupported address type : " + saddr);
818 }
819 data = new byte[4];
820 i = readSocksReply(in, data);
821 SocketException ex = null;
822 int len, nport;
823 byte[] addr;
824 switch (data[1]) {
825 case REQUEST_OK:
826 // success!
827 switch(data[3]) {
828 case IPV4:
829 addr = new byte[4];
830 i = readSocksReply(in, addr);
831 if (i != 4)
832 throw new SocketException("Reply from SOCKS server badly formatted");
833 data = new byte[2];
834 i = readSocksReply(in, data);
835 if (i != 2)
836 throw new SocketException("Reply from SOCKS server badly formatted");
837 nport = ((int)data[0] & 0xff) << 8;
838 nport += ((int)data[1] & 0xff);
839 external_address =
840 new InetSocketAddress(new Inet4Address("", addr) , nport);
841 break;
842 case DOMAIN_NAME:
843 len = data[1];
844 byte[] host = new byte[len];
845 i = readSocksReply(in, host);
846 if (i != len)
847 throw new SocketException("Reply from SOCKS server badly formatted");
848 data = new byte[2];
849 i = readSocksReply(in, data);
850 if (i != 2)
851 throw new SocketException("Reply from SOCKS server badly formatted");
852 nport = ((int)data[0] & 0xff) << 8;
853 nport += ((int)data[1] & 0xff);
854 external_address = new InetSocketAddress(new String(host), nport);
855 break;
856 case IPV6:
857 len = data[1];
858 addr = new byte[len];
859 i = readSocksReply(in, addr);
860 if (i != len)
861 throw new SocketException("Reply from SOCKS server badly formatted");
862 data = new byte[2];
863 i = readSocksReply(in, data);
864 if (i != 2)
865 throw new SocketException("Reply from SOCKS server badly formatted");
866 nport = ((int)data[0] & 0xff) << 8;
867 nport += ((int)data[1] & 0xff);
868 external_address =
869 new InetSocketAddress(new Inet6Address("", addr), nport);
870 break;
871 }
872 break;
873 case GENERAL_FAILURE:
874 ex = new SocketException("SOCKS server general failure");
875 break;
876 case NOT_ALLOWED:
877 ex = new SocketException("SOCKS: Bind not allowed by ruleset");
878 break;
879 case NET_UNREACHABLE:
880 ex = new SocketException("SOCKS: Network unreachable");
881 break;
882 case HOST_UNREACHABLE:
883 ex = new SocketException("SOCKS: Host unreachable");
884 break;
885 case CONN_REFUSED:
886 ex = new SocketException("SOCKS: Connection refused");
887 break;
888 case TTL_EXPIRED:
889 ex = new SocketException("SOCKS: TTL expired");
890 break;
891 case CMD_NOT_SUPPORTED:
892 ex = new SocketException("SOCKS: Command not supported");
893 break;
894 case ADDR_TYPE_NOT_SUP:
895 ex = new SocketException("SOCKS: address type not supported");
896 break;
897 }
898 if (ex != null) {
899 in.close();
900 out.close();
901 cmdsock.close();
902 cmdsock = null;
903 throw ex;
904 }
905 cmdIn = in;
906 cmdOut = out;
907 }
908
909 /**
910 * Accepts a connection from a specific host.
911 *
912 * @param s the accepted connection.
913 * @param saddr the socket address of the host we do accept
914 * connection from
915 * @exception IOException if an I/O error occurs when accepting the
916 * connection.
917 */
918 protected void acceptFrom(SocketImpl s, InetSocketAddress saddr) throws IOException {
919 if (cmdsock == null) {
920 // Not a Socks ServerSocket.
921 return;
922 }
923 InputStream in = cmdIn;
924 // Sends the "SOCKS BIND" request.
925 socksBind(saddr);
926 in.read();
927 int i = in.read();
928 in.read();
929 SocketException ex = null;
930 int nport;
931 byte[] addr;
932 InetSocketAddress real_end = null;
933 switch (i) {
934 case REQUEST_OK:
935 // success!
936 i = in.read();
937 switch(i) {
938 case IPV4:
939 addr = new byte[4];
940 readSocksReply(in, addr);
941 nport = in.read() << 8;
942 nport += in.read();
943 real_end =
944 new InetSocketAddress(new Inet4Address("", addr) , nport);
945 break;
946 case DOMAIN_NAME:
947 int len = in.read();
948 addr = new byte[len];
949 readSocksReply(in, addr);
950 nport = in.read() << 8;
951 nport += in.read();
952 real_end = new InetSocketAddress(new String(addr), nport);
953 break;
954 case IPV6:
955 addr = new byte[16];
956 readSocksReply(in, addr);
957 nport = in.read() << 8;
958 nport += in.read();
959 real_end =
960 new InetSocketAddress(new Inet6Address("", addr), nport);
961 break;
962 }
963 break;
964 case GENERAL_FAILURE:
965 ex = new SocketException("SOCKS server general failure");
966 break;
967 case NOT_ALLOWED:
968 ex = new SocketException("SOCKS: Accept not allowed by ruleset");
969 break;
970 case NET_UNREACHABLE:
971 ex = new SocketException("SOCKS: Network unreachable");
972 break;
973 case HOST_UNREACHABLE:
974 ex = new SocketException("SOCKS: Host unreachable");
975 break;
976 case CONN_REFUSED:
977 ex = new SocketException("SOCKS: Connection refused");
978 break;
979 case TTL_EXPIRED:
980 ex = new SocketException("SOCKS: TTL expired");
981 break;
982 case CMD_NOT_SUPPORTED:
983 ex = new SocketException("SOCKS: Command not supported");
984 break;
985 case ADDR_TYPE_NOT_SUP:
986 ex = new SocketException("SOCKS: address type not supported");
987 break;
988 }
989 if (ex != null) {
990 cmdIn.close();
991 cmdOut.close();
992 cmdsock.close();
993 cmdsock = null;
994 throw ex;
995 }
996
997 /**
998 * This is where we have to do some fancy stuff.
999 * The datastream from the socket "accepted" by the proxy will
1000 * come through the cmdSocket. So we have to swap the socketImpls
1001 */
1002 if (s instanceof SocksSocketImpl) {
1003 ((SocksSocketImpl)s).external_address = real_end;
1004 }
1005 if (s instanceof PlainSocketImpl) {
1006 PlainSocketImpl psi = (PlainSocketImpl) s;
1007 psi.setInputStream((SocketInputStream) in);
1008 psi.setFileDescriptor(cmdsock.getImpl().getFileDescriptor());
1009 psi.setAddress(cmdsock.getImpl().getInetAddress());
1010 psi.setPort(cmdsock.getImpl().getPort());
1011 psi.setLocalPort(cmdsock.getImpl().getLocalPort());
1012 } else {
1013 s.fd = cmdsock.getImpl().fd;
1014 s.address = cmdsock.getImpl().address;
1015 s.port = cmdsock.getImpl().port;
1016 s.localport = cmdsock.getImpl().localport;
1017 }
1018
1019 // Need to do that so that the socket won't be closed
1020 // when the ServerSocket is closed by the user.
1021 // It kinds of detaches the Socket because it is now
1022 // used elsewhere.
1023 cmdsock = null;
1024 }
1025
1026
1027 /**
1028 * Returns the value of this socket's <code>address</code> field.
1029 *
1030 * @return the value of this socket's <code>address</code> field.
1031 * @see java.net.SocketImpl#address
1032 */
1033 @Override
1034 protected InetAddress getInetAddress() {
1035 if (external_address != null)
1036 return external_address.getAddress();
1037 else
1038 return super.getInetAddress();
1039 }
1040
1041 /**
1042 * Returns the value of this socket's <code>port</code> field.
1043 *
1044 * @return the value of this socket's <code>port</code> field.
1045 * @see java.net.SocketImpl#port
1046 */
1047 @Override
1048 protected int getPort() {
1049 if (external_address != null)
1050 return external_address.getPort();
1051 else
1052 return super.getPort();
1053 }
1054
1055 @Override
1056 protected int getLocalPort() {
1057 if (socket != null)
1058 return super.getLocalPort();
1059 if (external_address != null)
1060 return external_address.getPort();
1061 else
1062 return super.getLocalPort();
1063 }
1064
1065 @Override
1066 protected void close() throws IOException {
1067 if (cmdsock != null)
1068 cmdsock.close();
1069 cmdsock = null;
1070 super.close();
1071 }
1072
1073 private String getUserName() {
1074 String userName = "";
1075 if (applicationSetProxy) {
1076 try {
1077 userName = System.getProperty("user.name");
1078 } catch (SecurityException se) { /* swallow Exception */ }
1079 } else {
1080 userName = java.security.AccessController.doPrivileged(
1081 new sun.security.action.GetPropertyAction("user.name"));
1082 }
1083 return userName;
1084 }
1085}