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