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