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