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+ */
25+package java.net;
26+import java.io.IOException;
27+import java.io.InputStream;
28+import java.io.OutputStream;
29+import java.io.BufferedOutputStream;
30+import java.security.AccessController;
31+import java.security.PrivilegedExceptionAction;
32+import sun.net.SocksProxy;
33+import 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+
42+class 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+}