1 /*
2  * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
3  * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
4  *
5  *
6  *
7  *
8  *
9  *
10  *
11  *
12  *
13  *
14  *
15  *
16  *
17  *
18  *
19  *
20  *
21  *
22  *
23  *
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.PrivilegedAction;
32 import java.security.PrivilegedExceptionAction;
33 import sun.net.SocksProxy;
34 import sun.net.www.ParseUtil;
35 /* import org.ietf.jgss.*; */
36
37 /**
38  * SOCKS (V4 & V5) TCP socket implementation (RFC 1928).
39  * This is a subclass of PlainSocketImpl.
40  * Note this class should <b>NOT</b> be public.
41  */

42
43 class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
44     private String server = null;
45     private int serverPort = DEFAULT_PORT;
46     private InetSocketAddress external_address;
47     private boolean useV4 = false;
48     private Socket cmdsock = null;
49     private InputStream cmdIn = null;
50     private OutputStream cmdOut = null;
51     /* true if the Proxy has been set programatically */
52     private boolean applicationSetProxy;  /* false */
53
54
55     SocksSocketImpl() {
56         // Nothing needed
57     }
58
59     SocksSocketImpl(String server, int port) {
60         this.server = server;
61         this.serverPort = (port == -1 ? DEFAULT_PORT : port);
62     }
63
64     SocksSocketImpl(Proxy proxy) {
65         SocketAddress a = proxy.address();
66         if (a instanceof InetSocketAddress) {
67             InetSocketAddress ad = (InetSocketAddress) a;
68             // Use getHostString() to avoid reverse lookups
69             server = ad.getHostString();
70             serverPort = ad.getPort();
71         }
72     }
73
74     void setV4() {
75         useV4 = true;
76     }
77
78     private synchronized void privilegedConnect(final String host,
79                                               final int port,
80                                               final int timeout)
81          throws IOException
82     {
83         try {
84             AccessController.doPrivileged(
85                 new java.security.PrivilegedExceptionAction<Void>() {
86                     public Void run() throws IOException {
87                               superConnectServer(host, port, timeout);
88                               cmdIn = getInputStream();
89                               cmdOut = getOutputStream();
90                               return null;
91                           }
92                       });
93         } catch (java.security.PrivilegedActionException pae) {
94             throw (IOException) pae.getException();
95         }
96     }
97
98     private void superConnectServer(String host, int port,
99                                     int timeout) throws IOException {
100         super.connect(new InetSocketAddress(host, port), timeout);
101     }
102
103     private static int remainingMillis(long deadlineMillis) throws IOException {
104         if (deadlineMillis == 0L)
105             return 0;
106
107         final long remaining = deadlineMillis - System.currentTimeMillis();
108         if (remaining > 0)
109             return (int) remaining;
110
111         throw new SocketTimeoutException();
112     }
113
114     private int readSocksReply(InputStream in, byte[] data) throws IOException {
115         return readSocksReply(in, data, 0L);
116     }
117
118     private int readSocksReply(InputStream in, byte[] data, long deadlineMillis) throws IOException {
119         int len = data.length;
120         int received = 0;
121         for (int attempts = 0; received < len && attempts < 3; attempts++) {
122             int count;
123             try {
124                 count = ((SocketInputStream)in).read(data, received, len - received, remainingMillis(deadlineMillis));
125             } catch (SocketTimeoutException e) {
126                 throw new SocketTimeoutException("Connect timed out");
127             }
128             if (count < 0)
129                 throw new SocketException("Malformed reply from SOCKS server");
130             received += count;
131         }
132         return received;
133     }
134
135     /**
136      * Provides the authentication machanism required by the proxy.
137      */

138     private boolean authenticate(byte method, InputStream in,
139                                  BufferedOutputStream out) throws IOException {
140         return authenticate(method, in, out, 0L);
141     }
142
143     private boolean authenticate(byte method, InputStream in,
144                                  BufferedOutputStream out,
145                                  long deadlineMillis) throws IOException {
146         // No Authentication required. We're done then!
147         if (method == NO_AUTH)
148             return true;
149         /**
150          * User/Password authentication. Try, in that order :
151          * - The application provided Authenticator, if any
152          * - the user.name & no password (backward compatibility behavior).
153          */

154         if (method == USER_PASSW) {
155             String userName;
156             String password = null;
157             final InetAddress addr = InetAddress.getByName(server);
158             PasswordAuthentication pw =
159                 java.security.AccessController.doPrivileged(
160                     new java.security.PrivilegedAction<PasswordAuthentication>() {
161                         public PasswordAuthentication run() {
162                                 return Authenticator.requestPasswordAuthentication(
163                                        server, addr, serverPort, "SOCKS5""SOCKS authentication"null);
164                             }
165                         });
166             if (pw != null) {
167                 userName = pw.getUserName();
168                 password = new String(pw.getPassword());
169             } else {
170                 userName = java.security.AccessController.doPrivileged(
171                         new sun.security.action.GetPropertyAction("user.name"));
172             }
173             if (userName == null)
174                 return false;
175             out.write(1);
176             out.write(userName.length());
177             try {
178                 out.write(userName.getBytes("ISO-8859-1"));
179             } catch (java.io.UnsupportedEncodingException uee) {
180                 assert false;
181             }
182             if (password != null) {
183                 out.write(password.length());
184                 try {
185                     out.write(password.getBytes("ISO-8859-1"));
186                 } catch (java.io.UnsupportedEncodingException uee) {
187                     assert false;
188                 }
189             } else
190                 out.write(0);
191             out.flush();
192             byte[] data = new byte[2];
193             int i = readSocksReply(in, data, deadlineMillis);
194             if (i != 2 || data[1] != 0) {
195                 /* RFC 1929 specifies that the connection MUST be closed if
196                    authentication fails */

197                 out.close();
198                 in.close();
199                 return false;
200             }
201             /* Authentication succeeded */
202             return true;
203         }
204         /**
205          * GSSAPI authentication mechanism.
206          * Unfortunately the RFC seems out of sync with the Reference
207          * implementation. I'll leave this in for future completion.
208          */

209 //      if (method == GSSAPI) {
210 //          try {
211 //              GSSManager manager = GSSManager.getInstance();
212 //              GSSName name = manager.createName("SERVICE:socks@"+server,
213 //                                                   null);
214 //              GSSContext context = manager.createContext(name, nullnull,
215 //                                                         GSSContext.DEFAULT_LIFETIME);
216 //              context.requestMutualAuth(true);
217 //              context.requestReplayDet(true);
218 //              context.requestSequenceDet(true);
219 //              context.requestCredDeleg(true);
220 //              byte []inToken = new byte[0];
221 //              while (!context.isEstablished()) {
222 //                  byte[] outToken
223 //                      = context.initSecContext(inToken, 0, inToken.length);
224 //                  // send the output token if generated
225 //                  if (outToken != null) {
226 //                      out.write(1);
227 //                      out.write(1);
228 //                      out.writeShort(outToken.length);
229 //                      out.write(outToken);
230 //                      out.flush();
231 //                      data = new byte[2];
232 //                      i = readSocksReply(in, data, deadlineMillis);
233 //                      if (i != 2 || data[1] == 0xff) {
234 //                          in.close();
235 //                          out.close();
236 //                          return false;
237 //                      }
238 //                      i = readSocksReply(in, data, deadlineMillis);
239 //                      int len = 0;
240 //                      len = ((int)data[0] & 0xff) << 8;
241 //                      len += data[1];
242 //                      data = new byte[len];
243 //                      i = readSocksReply(in, data, deadlineMillis);
244 //                      if (i == len)
245 //                          return true;
246 //                      in.close();
247 //                      out.close();
248 //                  }
249 //              }
250 //          } catch (GSSException e) {
251 //              /* RFC 1961 states that if Context initialisation fails the connection
252 //                 MUST be closed */

253 //              e.printStackTrace();
254 //              in.close();
255 //              out.close();
256 //          }
257 //      }
258         return false;
259     }
260
261     private void connectV4(InputStream in, OutputStream out,
262                            InetSocketAddress endpoint,
263                            long deadlineMillis) throws IOException {
264         if (!(endpoint.getAddress() instanceof Inet4Address)) {
265             throw new SocketException("SOCKS V4 requires IPv4 only addresses");
266         }
267         out.write(PROTO_VERS4);
268         out.write(CONNECT);
269         out.write((endpoint.getPort() >> 8) & 0xff);
270         out.write((endpoint.getPort() >> 0) & 0xff);
271         out.write(endpoint.getAddress().getAddress());
272         String userName = getUserName();
273         try {
274             out.write(userName.getBytes("ISO-8859-1"));
275         } catch (java.io.UnsupportedEncodingException uee) {
276             assert false;
277         }
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
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<ProxySelector>() {
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                 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 initialized 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 = AccessController.doPrivileged(
594                         new PrivilegedAction<InetAddress>() {
595                             public InetAddress run() {
596                                 return cmdsock.getLocalAddress();
597
598                             }
599                         });
600             addr1 = naddr.getAddress();
601         }
602         out.write(PROTO_VERS4);
603         out.write(BIND);
604         out.write((super.getLocalPort() >> 8) & 0xff);
605         out.write((super.getLocalPort() >> 0) & 0xff);
606         out.write(addr1);
607         String userName = getUserName();
608         try {
609             out.write(userName.getBytes("ISO-8859-1"));
610         } catch (java.io.UnsupportedEncodingException uee) {
611             assert false;
612         }
613         out.write(0);
614         out.flush();
615         byte[] data = new byte[8];
616         int n = readSocksReply(in, data);
617         if (n != 8)
618             throw new SocketException("Reply from SOCKS server has bad length: " + n);
619         if (data[0] != 0 && data[0] != 4)
620             throw new SocketException("Reply from SOCKS server has bad version");
621         SocketException ex = null;
622         switch (data[1]) {
623         case 90:
624             // Success!
625             external_address = new InetSocketAddress(baddr, lport);
626             break;
627         case 91:
628             ex = new SocketException("SOCKS request rejected");
629             break;
630         case 92:
631             ex = new SocketException("SOCKS server couldn't reach destination");
632             break;
633         case 93:
634             ex = new SocketException("SOCKS authentication failed");
635             break;
636         default:
637             ex = new SocketException("Reply from SOCKS server contains bad status");
638             break;
639         }
640         if (ex != null) {
641             in.close();
642             out.close();
643             throw ex;
644         }
645
646     }
647
648     /**
649      * Sends the Bind request to the SOCKS proxy. In the SOCKS protocol, bind
650      * means "accept incoming connection from", so the SocketAddress is the
651      * the one of the host we do accept connection from.
652      *
653      * @param      saddr   the Socket address of the remote host.
654      * @exception  IOException  if an I/O error occurs when binding this socket.
655      */

656     protected synchronized void socksBind(InetSocketAddress saddr) throws IOException {
657         if (socket != null) {
658             // this is a client socket, not a server socket, don't
659             // call the SOCKS proxy for a bind!
660             return;
661         }
662
663         // Connects to the SOCKS server
664
665         if (server == null) {
666             // This is the general case
667             // server is not null only when the socket was created with a
668             // specified proxy in which case it does bypass the ProxySelector
669             ProxySelector sel = java.security.AccessController.doPrivileged(
670                 new java.security.PrivilegedAction<ProxySelector>() {
671                     public ProxySelector run() {
672                             return ProxySelector.getDefault();
673                         }
674                     });
675             if (sel == null) {
676                 /*
677                  * No default proxySelector --> direct connection
678                  */

679                 return;
680             }
681             URI uri;
682             // Use getHostString() to avoid reverse lookups
683             String host = saddr.getHostString();
684             // IPv6 litteral?
685             if (saddr.getAddress() instanceof Inet6Address &&
686                 (!host.startsWith("[")) && (host.indexOf(":") >= 0)) {
687                 host = "[" + host + "]";
688             }
689             try {
690                 uri = new URI("serversocket://" + ParseUtil.encodePath(host) + ":"+ saddr.getPort());
691             } catch (URISyntaxException e) {
692                 // This shouldn't happen
693                 assert false : e;
694                 uri = null;
695             }
696             Proxy p = null;
697             Exception savedExc = null;
698             java.util.Iterator<Proxy> iProxy = null;
699             iProxy = sel.select(uri).iterator();
700             if (iProxy == null || !(iProxy.hasNext())) {
701                 return;
702             }
703             while (iProxy.hasNext()) {
704                 p = iProxy.next();
705                 if (p == null || p.type() != Proxy.Type.SOCKS) {
706                     return;
707                 }
708
709                 if (!(p.address() instanceof InetSocketAddress))
710                     throw new SocketException("Unknown address type for proxy: " + p);
711                 // Use getHostString() to avoid reverse lookups
712                 server = ((InetSocketAddress) p.address()).getHostString();
713                 serverPort = ((InetSocketAddress) p.address()).getPort();
714                 if (p instanceof SocksProxy) {
715                     if (((SocksProxy)p).protocolVersion() == 4) {
716                         useV4 = true;
717                     }
718                 }
719
720                 // Connects to the SOCKS server
721                 try {
722                     AccessController.doPrivileged(
723                         new PrivilegedExceptionAction<Void>() {
724                             public Void run() throws Exception {
725                                 cmdsock = new Socket(new PlainSocketImpl());
726                                 cmdsock.connect(new InetSocketAddress(server, serverPort));
727                                 cmdIn = cmdsock.getInputStream();
728                                 cmdOut = cmdsock.getOutputStream();
729                                 return null;
730                             }
731                         });
732                 } catch (Exception e) {
733                     // Ooops, let's notify the ProxySelector
734                     sel.connectFailed(uri,p.address(),new SocketException(e.getMessage()));
735                     server = null;
736                     serverPort = -1;
737                     cmdsock = null;
738                     savedExc = e;
739                     // Will continue the while loop and try the next proxy
740                 }
741             }
742
743             /*
744              * If server is still null at this point, none of the proxy
745              * worked
746              */

747             if (server == null || cmdsock == null) {
748                 throw new SocketException("Can't connect to SOCKS proxy:"
749                                           + savedExc.getMessage());
750             }
751         } else {
752             try {
753                 AccessController.doPrivileged(
754                     new PrivilegedExceptionAction<Void>() {
755                         public Void run() throws Exception {
756                             cmdsock = new Socket(new PlainSocketImpl());
757                             cmdsock.connect(new InetSocketAddress(server, serverPort));
758                             cmdIn = cmdsock.getInputStream();
759                             cmdOut = cmdsock.getOutputStream();
760                             return null;
761                         }
762                     });
763             } catch (Exception e) {
764                 throw new SocketException(e.getMessage());
765             }
766         }
767         BufferedOutputStream out = new BufferedOutputStream(cmdOut, 512);
768         InputStream in = cmdIn;
769         if (useV4) {
770             bindV4(in, out, saddr.getAddress(), saddr.getPort());
771             return;
772         }
773         out.write(PROTO_VERS);
774         out.write(2);
775         out.write(NO_AUTH);
776         out.write(USER_PASSW);
777         out.flush();
778         byte[] data = new byte[2];
779         int i = readSocksReply(in, data);
780         if (i != 2 || ((int)data[0]) != PROTO_VERS) {
781             // Maybe it's not a V5 sever after all
782             // Let's try V4 before we give up
783             bindV4(in, out, saddr.getAddress(), saddr.getPort());
784             return;
785         }
786         if (((int)data[1]) == NO_METHODS)
787             throw new SocketException("SOCKS : No acceptable methods");
788         if (!authenticate(data[1], in, out)) {
789             throw new SocketException("SOCKS : authentication failed");
790         }
791         // We're OK. Let's issue the BIND command.
792         out.write(PROTO_VERS);
793         out.write(BIND);
794         out.write(0);
795         int lport = saddr.getPort();
796         if (saddr.isUnresolved()) {
797             out.write(DOMAIN_NAME);
798             out.write(saddr.getHostName().length());
799             try {
800                 out.write(saddr.getHostName().getBytes("ISO-8859-1"));
801             } catch (java.io.UnsupportedEncodingException uee) {
802                 assert false;
803             }
804             out.write((lport >> 8) & 0xff);
805             out.write((lport >> 0) & 0xff);
806         } else if (saddr.getAddress() instanceof Inet4Address) {
807             byte[] addr1 = saddr.getAddress().getAddress();
808             out.write(IPV4);
809             out.write(addr1);
810             out.write((lport >> 8) & 0xff);
811             out.write((lport >> 0) & 0xff);
812             out.flush();
813         } else if (saddr.getAddress() instanceof Inet6Address) {
814             byte[] addr1 = saddr.getAddress().getAddress();
815             out.write(IPV6);
816             out.write(addr1);
817             out.write((lport >> 8) & 0xff);
818             out.write((lport >> 0) & 0xff);
819             out.flush();
820         } else {
821             cmdsock.close();
822             throw new SocketException("unsupported address type : " + saddr);
823         }
824         data = new byte[4];
825         i = readSocksReply(in, data);
826         SocketException ex = null;
827         int len, nport;
828         byte[] addr;
829         switch (data[1]) {
830         case REQUEST_OK:
831             // success!
832             switch(data[3]) {
833             case IPV4:
834                 addr = new byte[4];
835                 i = readSocksReply(in, addr);
836                 if (i != 4)
837                     throw new SocketException("Reply from SOCKS server badly formatted");
838                 data = new byte[2];
839                 i = readSocksReply(in, data);
840                 if (i != 2)
841                     throw new SocketException("Reply from SOCKS server badly formatted");
842                 nport = ((int)data[0] & 0xff) << 8;
843                 nport += ((int)data[1] & 0xff);
844                 external_address =
845                     new InetSocketAddress(new Inet4Address("", addr) , nport);
846                 break;
847             case DOMAIN_NAME:
848                 len = data[1];
849                 byte[] host = new byte[len];
850                 i = readSocksReply(in, host);
851                 if (i != len)
852                     throw new SocketException("Reply from SOCKS server badly formatted");
853                 data = new byte[2];
854                 i = readSocksReply(in, data);
855                 if (i != 2)
856                     throw new SocketException("Reply from SOCKS server badly formatted");
857                 nport = ((int)data[0] & 0xff) << 8;
858                 nport += ((int)data[1] & 0xff);
859                 external_address = new InetSocketAddress(new String(host), nport);
860                 break;
861             case IPV6:
862                 len = data[1];
863                 addr = new byte[len];
864                 i = readSocksReply(in, addr);
865                 if (i != len)
866                     throw new SocketException("Reply from SOCKS server badly formatted");
867                 data = new byte[2];
868                 i = readSocksReply(in, data);
869                 if (i != 2)
870                     throw new SocketException("Reply from SOCKS server badly formatted");
871                 nport = ((int)data[0] & 0xff) << 8;
872                 nport += ((int)data[1] & 0xff);
873                 external_address =
874                     new InetSocketAddress(new Inet6Address("", addr), nport);
875                 break;
876             }
877             break;
878         case GENERAL_FAILURE:
879             ex = new SocketException("SOCKS server general failure");
880             break;
881         case NOT_ALLOWED:
882             ex = new SocketException("SOCKS: Bind not allowed by ruleset");
883             break;
884         case NET_UNREACHABLE:
885             ex = new SocketException("SOCKS: Network unreachable");
886             break;
887         case HOST_UNREACHABLE:
888             ex = new SocketException("SOCKS: Host unreachable");
889             break;
890         case CONN_REFUSED:
891             ex = new SocketException("SOCKS: Connection refused");
892             break;
893         case TTL_EXPIRED:
894             ex =  new SocketException("SOCKS: TTL expired");
895             break;
896         case CMD_NOT_SUPPORTED:
897             ex = new SocketException("SOCKS: Command not supported");
898             break;
899         case ADDR_TYPE_NOT_SUP:
900             ex = new SocketException("SOCKS: address type not supported");
901             break;
902         }
903         if (ex != null) {
904             in.close();
905             out.close();
906             cmdsock.close();
907             cmdsock = null;
908             throw ex;
909         }
910         cmdIn = in;
911         cmdOut = out;
912     }
913
914     /**
915      * Accepts a connection from a specific host.
916      *
917      * @param      s   the accepted connection.
918      * @param      saddr the socket address of the host we do accept
919      *               connection from
920      * @exception  IOException  if an I/O error occurs when accepting the
921      *               connection.
922      */

923     protected void acceptFrom(SocketImpl s, InetSocketAddress saddr) throws IOException {
924         if (cmdsock == null) {
925             // Not a Socks ServerSocket.
926             return;
927         }
928         InputStream in = cmdIn;
929         // Sends the "SOCKS BIND" request.
930         socksBind(saddr);
931         in.read();
932         int i = in.read();
933         in.read();
934         SocketException ex = null;
935         int nport;
936         byte[] addr;
937         InetSocketAddress real_end = null;
938         switch (i) {
939         case REQUEST_OK:
940             // success!
941             i = in.read();
942             switch(i) {
943             case IPV4:
944                 addr = new byte[4];
945                 readSocksReply(in, addr);
946                 nport = in.read() << 8;
947                 nport += in.read();
948                 real_end =
949                     new InetSocketAddress(new Inet4Address("", addr) , nport);
950                 break;
951             case DOMAIN_NAME:
952                 int len = in.read();
953                 addr = new byte[len];
954                 readSocksReply(in, addr);
955                 nport = in.read() << 8;
956                 nport += in.read();
957                 real_end = new InetSocketAddress(new String(addr), nport);
958                 break;
959             case IPV6:
960                 addr = new byte[16];
961                 readSocksReply(in, addr);
962                 nport = in.read() << 8;
963                 nport += in.read();
964                 real_end =
965                     new InetSocketAddress(new Inet6Address("", addr), nport);
966                 break;
967             }
968             break;
969         case GENERAL_FAILURE:
970             ex = new SocketException("SOCKS server general failure");
971             break;
972         case NOT_ALLOWED:
973             ex = new SocketException("SOCKS: Accept not allowed by ruleset");
974             break;
975         case NET_UNREACHABLE:
976             ex = new SocketException("SOCKS: Network unreachable");
977             break;
978         case HOST_UNREACHABLE:
979             ex = new SocketException("SOCKS: Host unreachable");
980             break;
981         case CONN_REFUSED:
982             ex = new SocketException("SOCKS: Connection refused");
983             break;
984         case TTL_EXPIRED:
985             ex =  new SocketException("SOCKS: TTL expired");
986             break;
987         case CMD_NOT_SUPPORTED:
988             ex = new SocketException("SOCKS: Command not supported");
989             break;
990         case ADDR_TYPE_NOT_SUP:
991             ex = new SocketException("SOCKS: address type not supported");
992             break;
993         }
994         if (ex != null) {
995             cmdIn.close();
996             cmdOut.close();
997             cmdsock.close();
998             cmdsock = null;
999             throw ex;
1000         }
1001
1002         /**
1003          * This is where we have to do some fancy stuff.
1004          * The datastream from the socket "accepted" by the proxy will
1005          * come through the cmdSocket. So we have to swap the socketImpls
1006          */

1007         if (s instanceof SocksSocketImpl) {
1008             ((SocksSocketImpl)s).external_address = real_end;
1009         }
1010         if (s instanceof PlainSocketImpl) {
1011             PlainSocketImpl psi = (PlainSocketImpl) s;
1012             psi.setInputStream((SocketInputStream) in);
1013             psi.setFileDescriptor(cmdsock.getImpl().getFileDescriptor());
1014             psi.setAddress(cmdsock.getImpl().getInetAddress());
1015             psi.setPort(cmdsock.getImpl().getPort());
1016             psi.setLocalPort(cmdsock.getImpl().getLocalPort());
1017         } else {
1018             s.fd = cmdsock.getImpl().fd;
1019             s.address = cmdsock.getImpl().address;
1020             s.port = cmdsock.getImpl().port;
1021             s.localport = cmdsock.getImpl().localport;
1022         }
1023
1024         // Need to do that so that the socket won't be closed
1025         // when the ServerSocket is closed by the user.
1026         // It kinds of detaches the Socket because it is now
1027         // used elsewhere.
1028         cmdsock = null;
1029     }
1030
1031
1032     /**
1033      * Returns the value of this socket's {@code address} field.
1034      *
1035      * @return  the value of this socket's {@code address} field.
1036      * @see     java.net.SocketImpl#address
1037      */

1038     @Override
1039     protected InetAddress getInetAddress() {
1040         if (external_address != null)
1041             return external_address.getAddress();
1042         else
1043             return super.getInetAddress();
1044     }
1045
1046     /**
1047      * Returns the value of this socket's {@code port} field.
1048      *
1049      * @return  the value of this socket's {@code port} field.
1050      * @see     java.net.SocketImpl#port
1051      */

1052     @Override
1053     protected int getPort() {
1054         if (external_address != null)
1055             return external_address.getPort();
1056         else
1057             return super.getPort();
1058     }
1059
1060     @Override
1061     protected int getLocalPort() {
1062         if (socket != null)
1063             return super.getLocalPort();
1064         if (external_address != null)
1065             return external_address.getPort();
1066         else
1067             return super.getLocalPort();
1068     }
1069
1070     @Override
1071     protected void close() throws IOException {
1072         if (cmdsock != null)
1073             cmdsock.close();
1074         cmdsock = null;
1075         super.close();
1076     }
1077
1078     private String getUserName() {
1079         String userName = "";
1080         if (applicationSetProxy) {
1081             try {
1082                 userName = System.getProperty("user.name");
1083             } catch (SecurityException se) { /* swallow Exception */ }
1084         } else {
1085             userName = java.security.AccessController.doPrivileged(
1086                 new sun.security.action.GetPropertyAction("user.name"));
1087         }
1088         return userName;
1089     }
1090 }
1091
Powered by JavaMelody