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