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