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 }