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 SocksSocketImpl()55 SocksSocketImpl() { 56 // Nothing needed 57 } 58 SocksSocketImpl(String server, int port)59 SocksSocketImpl(String server, int port) { 60 this.server = server; 61 this.serverPort = (port == -1 ? DEFAULT_PORT : port); 62 } 63 SocksSocketImpl(Proxy proxy)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 setV4()74 void setV4() { 75 useV4 = true; 76 } 77 privilegedConnect(final String host, final int port, final int timeout)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 superConnectServer(String host, int port, int timeout)98 private void superConnectServer(String host, int port, 99 int timeout) throws IOException { 100 super.connect(new InetSocketAddress(host, port), timeout); 101 } 102 remainingMillis(long deadlineMillis)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 readSocksReply(InputStream in, byte[] data)114 private int readSocksReply(InputStream in, byte[] data) throws IOException { 115 return readSocksReply(in, data, 0L); 116 } 117 readSocksReply(InputStream in, byte[] data, long deadlineMillis)118 private int readSocksReply(InputStream in, byte[] data, long deadlineMillis) throws IOException { 119 int len = data.length; 120 int received = 0; 121 while (received < len) { 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 */ authenticate(byte method, InputStream in, BufferedOutputStream out)138 private boolean authenticate(byte method, InputStream in, 139 BufferedOutputStream out) throws IOException { 140 return authenticate(method, in, out, 0L); 141 } 142 authenticate(byte method, InputStream in, BufferedOutputStream out, long deadlineMillis)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 connectV4(InputStream in, OutputStream out, InetSocketAddress endpoint, long deadlineMillis)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 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 // 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 byte[] lenByte = new byte[1]; 532 i = readSocksReply(in, lenByte, deadlineMillis); 533 if (i != 1) 534 throw new SocketException("Reply from SOCKS server badly formatted"); 535 len = lenByte[0] & 0xFF; 536 byte[] host = new byte[len]; 537 i = readSocksReply(in, host, deadlineMillis); 538 if (i != len) 539 throw new SocketException("Reply from SOCKS server badly formatted"); 540 data = new byte[2]; 541 i = readSocksReply(in, data, deadlineMillis); 542 if (i != 2) 543 throw new SocketException("Reply from SOCKS server badly formatted"); 544 break; 545 case IPV6: 546 len = 16; 547 addr = new byte[len]; 548 i = readSocksReply(in, addr, deadlineMillis); 549 if (i != len) 550 throw new SocketException("Reply from SOCKS server badly formatted"); 551 data = new byte[2]; 552 i = readSocksReply(in, data, deadlineMillis); 553 if (i != 2) 554 throw new SocketException("Reply from SOCKS server badly formatted"); 555 break; 556 default: 557 ex = new SocketException("Reply from SOCKS server contains wrong code"); 558 break; 559 } 560 break; 561 case GENERAL_FAILURE: 562 ex = new SocketException("SOCKS server general failure"); 563 break; 564 case NOT_ALLOWED: 565 ex = new SocketException("SOCKS: Connection not allowed by ruleset"); 566 break; 567 case NET_UNREACHABLE: 568 ex = new SocketException("SOCKS: Network unreachable"); 569 break; 570 case HOST_UNREACHABLE: 571 ex = new SocketException("SOCKS: Host unreachable"); 572 break; 573 case CONN_REFUSED: 574 ex = new SocketException("SOCKS: Connection refused"); 575 break; 576 case TTL_EXPIRED: 577 ex = new SocketException("SOCKS: TTL expired"); 578 break; 579 case CMD_NOT_SUPPORTED: 580 ex = new SocketException("SOCKS: Command not supported"); 581 break; 582 case ADDR_TYPE_NOT_SUP: 583 ex = new SocketException("SOCKS: address type not supported"); 584 break; 585 } 586 if (ex != null) { 587 in.close(); 588 out.close(); 589 throw ex; 590 } 591 external_address = epoint; 592 } 593 594 // Android-removed: Dead code. bindV4, socksBind, acceptFrom methods. 595 /* 596 private void bindV4(InputStream in, OutputStream out, 597 InetAddress baddr, 598 int lport) throws IOException { 599 if (!(baddr instanceof Inet4Address)) { 600 throw new SocketException("SOCKS V4 requires IPv4 only addresses"); 601 } 602 super.bind(baddr, lport); 603 byte[] addr1 = baddr.getAddress(); 604 /* Test for AnyLocal * 605 InetAddress naddr = baddr; 606 if (naddr.isAnyLocalAddress()) { 607 naddr = AccessController.doPrivileged( 608 new PrivilegedAction<InetAddress>() { 609 public InetAddress run() { 610 return cmdsock.getLocalAddress(); 611 612 } 613 }); 614 addr1 = naddr.getAddress(); 615 } 616 out.write(PROTO_VERS4); 617 out.write(BIND); 618 out.write((super.getLocalPort() >> 8) & 0xff); 619 out.write((super.getLocalPort() >> 0) & 0xff); 620 out.write(addr1); 621 String userName = getUserName(); 622 try { 623 out.write(userName.getBytes("ISO-8859-1")); 624 } catch (java.io.UnsupportedEncodingException uee) { 625 assert false; 626 } 627 out.write(0); 628 out.flush(); 629 byte[] data = new byte[8]; 630 int n = readSocksReply(in, data); 631 if (n != 8) 632 throw new SocketException("Reply from SOCKS server has bad length: " + n); 633 if (data[0] != 0 && data[0] != 4) 634 throw new SocketException("Reply from SOCKS server has bad version"); 635 SocketException ex = null; 636 switch (data[1]) { 637 case 90: 638 // Success! 639 external_address = new InetSocketAddress(baddr, lport); 640 break; 641 case 91: 642 ex = new SocketException("SOCKS request rejected"); 643 break; 644 case 92: 645 ex = new SocketException("SOCKS server couldn't reach destination"); 646 break; 647 case 93: 648 ex = new SocketException("SOCKS authentication failed"); 649 break; 650 default: 651 ex = new SocketException("Reply from SOCKS server contains bad status"); 652 break; 653 } 654 if (ex != null) { 655 in.close(); 656 out.close(); 657 throw ex; 658 } 659 660 } 661 662 /** 663 * Sends the Bind request to the SOCKS proxy. In the SOCKS protocol, bind 664 * means "accept incoming connection from", so the SocketAddress is the 665 * the one of the host we do accept connection from. 666 * 667 * @param saddr the Socket address of the remote host. 668 * @exception IOException if an I/O error occurs when binding this socket. 669 * 670 protected synchronized void socksBind(InetSocketAddress saddr) throws IOException { 671 if (socket != null) { 672 // this is a client socket, not a server socket, don't 673 // call the SOCKS proxy for a bind! 674 return; 675 } 676 677 // Connects to the SOCKS server 678 679 if (server == null) { 680 // This is the general case 681 // server is not null only when the socket was created with a 682 // specified proxy in which case it does bypass the ProxySelector 683 ProxySelector sel = java.security.AccessController.doPrivileged( 684 new java.security.PrivilegedAction<ProxySelector>() { 685 public ProxySelector run() { 686 return ProxySelector.getDefault(); 687 } 688 }); 689 if (sel == null) { 690 /* 691 * No default proxySelector --> direct connection 692 * 693 return; 694 } 695 URI uri; 696 // Use getHostString() to avoid reverse lookups 697 String host = saddr.getHostString(); 698 // IPv6 litteral? 699 if (saddr.getAddress() instanceof Inet6Address && 700 (!host.startsWith("[")) && (host.indexOf(":") >= 0)) { 701 host = "[" + host + "]"; 702 } 703 try { 704 uri = new URI("serversocket://" + ParseUtil.encodePath(host) + ":"+ saddr.getPort()); 705 } catch (URISyntaxException e) { 706 // This shouldn't happen 707 assert false : e; 708 uri = null; 709 } 710 Proxy p = null; 711 Exception savedExc = null; 712 java.util.Iterator<Proxy> iProxy = null; 713 iProxy = sel.select(uri).iterator(); 714 if (iProxy == null || !(iProxy.hasNext())) { 715 return; 716 } 717 while (iProxy.hasNext()) { 718 p = iProxy.next(); 719 if (p == null || p.type() != Proxy.Type.SOCKS) { 720 return; 721 } 722 723 if (!(p.address() instanceof InetSocketAddress)) 724 throw new SocketException("Unknown address type for proxy: " + p); 725 // Use getHostString() to avoid reverse lookups 726 server = ((InetSocketAddress) p.address()).getHostString(); 727 serverPort = ((InetSocketAddress) p.address()).getPort(); 728 if (p instanceof SocksProxy) { 729 if (((SocksProxy)p).protocolVersion() == 4) { 730 useV4 = true; 731 } 732 } 733 734 // Connects to the SOCKS server 735 try { 736 AccessController.doPrivileged( 737 new PrivilegedExceptionAction<Void>() { 738 public Void run() throws Exception { 739 cmdsock = new Socket(new PlainSocketImpl()); 740 cmdsock.connect(new InetSocketAddress(server, serverPort)); 741 cmdIn = cmdsock.getInputStream(); 742 cmdOut = cmdsock.getOutputStream(); 743 return null; 744 } 745 }); 746 } catch (Exception e) { 747 // Ooops, let's notify the ProxySelector 748 sel.connectFailed(uri,p.address(),new SocketException(e.getMessage())); 749 server = null; 750 serverPort = -1; 751 cmdsock = null; 752 savedExc = e; 753 // Will continue the while loop and try the next proxy 754 } 755 } 756 757 /* 758 * If server is still null at this point, none of the proxy 759 * worked 760 * 761 if (server == null || cmdsock == null) { 762 throw new SocketException("Can't connect to SOCKS proxy:" 763 + savedExc.getMessage()); 764 } 765 } else { 766 try { 767 AccessController.doPrivileged( 768 new PrivilegedExceptionAction<Void>() { 769 public Void run() throws Exception { 770 cmdsock = new Socket(new PlainSocketImpl()); 771 cmdsock.connect(new InetSocketAddress(server, serverPort)); 772 cmdIn = cmdsock.getInputStream(); 773 cmdOut = cmdsock.getOutputStream(); 774 return null; 775 } 776 }); 777 } catch (Exception e) { 778 throw new SocketException(e.getMessage()); 779 } 780 } 781 BufferedOutputStream out = new BufferedOutputStream(cmdOut, 512); 782 InputStream in = cmdIn; 783 if (useV4) { 784 bindV4(in, out, saddr.getAddress(), saddr.getPort()); 785 return; 786 } 787 out.write(PROTO_VERS); 788 out.write(2); 789 out.write(NO_AUTH); 790 out.write(USER_PASSW); 791 out.flush(); 792 byte[] data = new byte[2]; 793 int i = readSocksReply(in, data); 794 if (i != 2 || ((int)data[0]) != PROTO_VERS) { 795 // Maybe it's not a V5 sever after all 796 // Let's try V4 before we give up 797 bindV4(in, out, saddr.getAddress(), saddr.getPort()); 798 return; 799 } 800 if (((int)data[1]) == NO_METHODS) 801 throw new SocketException("SOCKS : No acceptable methods"); 802 if (!authenticate(data[1], in, out)) { 803 throw new SocketException("SOCKS : authentication failed"); 804 } 805 // We're OK. Let's issue the BIND command. 806 out.write(PROTO_VERS); 807 out.write(BIND); 808 out.write(0); 809 int lport = saddr.getPort(); 810 if (saddr.isUnresolved()) { 811 out.write(DOMAIN_NAME); 812 out.write(saddr.getHostName().length()); 813 try { 814 out.write(saddr.getHostName().getBytes("ISO-8859-1")); 815 } catch (java.io.UnsupportedEncodingException uee) { 816 assert false; 817 } 818 out.write((lport >> 8) & 0xff); 819 out.write((lport >> 0) & 0xff); 820 } else if (saddr.getAddress() instanceof Inet4Address) { 821 byte[] addr1 = saddr.getAddress().getAddress(); 822 out.write(IPV4); 823 out.write(addr1); 824 out.write((lport >> 8) & 0xff); 825 out.write((lport >> 0) & 0xff); 826 out.flush(); 827 } else if (saddr.getAddress() instanceof Inet6Address) { 828 byte[] addr1 = saddr.getAddress().getAddress(); 829 out.write(IPV6); 830 out.write(addr1); 831 out.write((lport >> 8) & 0xff); 832 out.write((lport >> 0) & 0xff); 833 out.flush(); 834 } else { 835 cmdsock.close(); 836 throw new SocketException("unsupported address type : " + saddr); 837 } 838 data = new byte[4]; 839 i = readSocksReply(in, data); 840 SocketException ex = null; 841 int len, nport; 842 byte[] addr; 843 switch (data[1]) { 844 case REQUEST_OK: 845 // success! 846 switch(data[3]) { 847 case IPV4: 848 addr = new byte[4]; 849 i = readSocksReply(in, addr); 850 if (i != 4) 851 throw new SocketException("Reply from SOCKS server badly formatted"); 852 data = new byte[2]; 853 i = readSocksReply(in, data); 854 if (i != 2) 855 throw new SocketException("Reply from SOCKS server badly formatted"); 856 nport = ((int)data[0] & 0xff) << 8; 857 nport += ((int)data[1] & 0xff); 858 external_address = 859 new InetSocketAddress(new Inet4Address("", addr) , nport); 860 break; 861 case DOMAIN_NAME: 862 len = data[1]; 863 byte[] host = new byte[len]; 864 i = readSocksReply(in, host); 865 if (i != len) 866 throw new SocketException("Reply from SOCKS server badly formatted"); 867 data = new byte[2]; 868 i = readSocksReply(in, data); 869 if (i != 2) 870 throw new SocketException("Reply from SOCKS server badly formatted"); 871 nport = ((int)data[0] & 0xff) << 8; 872 nport += ((int)data[1] & 0xff); 873 external_address = new InetSocketAddress(new String(host), nport); 874 break; 875 case IPV6: 876 len = data[1]; 877 addr = new byte[len]; 878 i = readSocksReply(in, addr); 879 if (i != len) 880 throw new SocketException("Reply from SOCKS server badly formatted"); 881 data = new byte[2]; 882 i = readSocksReply(in, data); 883 if (i != 2) 884 throw new SocketException("Reply from SOCKS server badly formatted"); 885 nport = ((int)data[0] & 0xff) << 8; 886 nport += ((int)data[1] & 0xff); 887 external_address = 888 new InetSocketAddress(new Inet6Address("", addr), nport); 889 break; 890 } 891 break; 892 case GENERAL_FAILURE: 893 ex = new SocketException("SOCKS server general failure"); 894 break; 895 case NOT_ALLOWED: 896 ex = new SocketException("SOCKS: Bind not allowed by ruleset"); 897 break; 898 case NET_UNREACHABLE: 899 ex = new SocketException("SOCKS: Network unreachable"); 900 break; 901 case HOST_UNREACHABLE: 902 ex = new SocketException("SOCKS: Host unreachable"); 903 break; 904 case CONN_REFUSED: 905 ex = new SocketException("SOCKS: Connection refused"); 906 break; 907 case TTL_EXPIRED: 908 ex = new SocketException("SOCKS: TTL expired"); 909 break; 910 case CMD_NOT_SUPPORTED: 911 ex = new SocketException("SOCKS: Command not supported"); 912 break; 913 case ADDR_TYPE_NOT_SUP: 914 ex = new SocketException("SOCKS: address type not supported"); 915 break; 916 } 917 if (ex != null) { 918 in.close(); 919 out.close(); 920 cmdsock.close(); 921 cmdsock = null; 922 throw ex; 923 } 924 cmdIn = in; 925 cmdOut = out; 926 } 927 928 /** 929 * Accepts a connection from a specific host. 930 * 931 * @param s the accepted connection. 932 * @param saddr the socket address of the host we do accept 933 * connection from 934 * @exception IOException if an I/O error occurs when accepting the 935 * connection. 936 * 937 protected void acceptFrom(SocketImpl s, InetSocketAddress saddr) throws IOException { 938 if (cmdsock == null) { 939 // Not a Socks ServerSocket. 940 return; 941 } 942 InputStream in = cmdIn; 943 // Sends the "SOCKS BIND" request. 944 socksBind(saddr); 945 in.read(); 946 int i = in.read(); 947 in.read(); 948 SocketException ex = null; 949 int nport; 950 byte[] addr; 951 InetSocketAddress real_end = null; 952 switch (i) { 953 case REQUEST_OK: 954 // success! 955 i = in.read(); 956 switch(i) { 957 case IPV4: 958 addr = new byte[4]; 959 readSocksReply(in, addr); 960 nport = in.read() << 8; 961 nport += in.read(); 962 real_end = 963 new InetSocketAddress(new Inet4Address("", addr) , nport); 964 break; 965 case DOMAIN_NAME: 966 int len = in.read(); 967 addr = new byte[len]; 968 readSocksReply(in, addr); 969 nport = in.read() << 8; 970 nport += in.read(); 971 real_end = new InetSocketAddress(new String(addr), nport); 972 break; 973 case IPV6: 974 addr = new byte[16]; 975 readSocksReply(in, addr); 976 nport = in.read() << 8; 977 nport += in.read(); 978 real_end = 979 new InetSocketAddress(new Inet6Address("", addr), nport); 980 break; 981 } 982 break; 983 case GENERAL_FAILURE: 984 ex = new SocketException("SOCKS server general failure"); 985 break; 986 case NOT_ALLOWED: 987 ex = new SocketException("SOCKS: Accept not allowed by ruleset"); 988 break; 989 case NET_UNREACHABLE: 990 ex = new SocketException("SOCKS: Network unreachable"); 991 break; 992 case HOST_UNREACHABLE: 993 ex = new SocketException("SOCKS: Host unreachable"); 994 break; 995 case CONN_REFUSED: 996 ex = new SocketException("SOCKS: Connection refused"); 997 break; 998 case TTL_EXPIRED: 999 ex = new SocketException("SOCKS: TTL expired"); 1000 break; 1001 case CMD_NOT_SUPPORTED: 1002 ex = new SocketException("SOCKS: Command not supported"); 1003 break; 1004 case ADDR_TYPE_NOT_SUP: 1005 ex = new SocketException("SOCKS: address type not supported"); 1006 break; 1007 } 1008 if (ex != null) { 1009 cmdIn.close(); 1010 cmdOut.close(); 1011 cmdsock.close(); 1012 cmdsock = null; 1013 throw ex; 1014 } 1015 1016 /** 1017 * This is where we have to do some fancy stuff. 1018 * The datastream from the socket "accepted" by the proxy will 1019 * come through the cmdSocket. So we have to swap the socketImpls 1020 * 1021 if (s instanceof SocksSocketImpl) { 1022 ((SocksSocketImpl)s).external_address = real_end; 1023 } 1024 if (s instanceof PlainSocketImpl) { 1025 PlainSocketImpl psi = (PlainSocketImpl) s; 1026 psi.setInputStream((SocketInputStream) in); 1027 psi.setFileDescriptor(cmdsock.getImpl().getFileDescriptor()); 1028 psi.setAddress(cmdsock.getImpl().getInetAddress()); 1029 psi.setPort(cmdsock.getImpl().getPort()); 1030 psi.setLocalPort(cmdsock.getImpl().getLocalPort()); 1031 } else { 1032 s.fd = cmdsock.getImpl().fd; 1033 s.address = cmdsock.getImpl().address; 1034 s.port = cmdsock.getImpl().port; 1035 s.localport = cmdsock.getImpl().localport; 1036 } 1037 1038 // Need to do that so that the socket won't be closed 1039 // when the ServerSocket is closed by the user. 1040 // It kinds of detaches the Socket because it is now 1041 // used elsewhere. 1042 cmdsock = null; 1043 } 1044 */ 1045 1046 /** 1047 * Returns the value of this socket's {@code address} field. 1048 * 1049 * @return the value of this socket's {@code address} field. 1050 * @see java.net.SocketImpl#address 1051 */ 1052 @Override getInetAddress()1053 protected InetAddress getInetAddress() { 1054 if (external_address != null) 1055 return external_address.getAddress(); 1056 else 1057 return super.getInetAddress(); 1058 } 1059 1060 /** 1061 * Returns the value of this socket's {@code port} field. 1062 * 1063 * @return the value of this socket's {@code port} field. 1064 * @see java.net.SocketImpl#port 1065 */ 1066 @Override getPort()1067 protected int getPort() { 1068 if (external_address != null) 1069 return external_address.getPort(); 1070 else 1071 return super.getPort(); 1072 } 1073 1074 @Override getLocalPort()1075 protected int getLocalPort() { 1076 if (socket != null) 1077 return super.getLocalPort(); 1078 if (external_address != null) 1079 return external_address.getPort(); 1080 else 1081 return super.getLocalPort(); 1082 } 1083 1084 @Override close()1085 protected void close() throws IOException { 1086 if (cmdsock != null) 1087 cmdsock.close(); 1088 cmdsock = null; 1089 super.close(); 1090 } 1091 getUserName()1092 private String getUserName() { 1093 String userName = ""; 1094 if (applicationSetProxy) { 1095 try { 1096 userName = System.getProperty("user.name"); 1097 } catch (SecurityException se) { /* swallow Exception */ } 1098 } else { 1099 userName = java.security.AccessController.doPrivileged( 1100 new sun.security.action.GetPropertyAction("user.name")); 1101 } 1102 return userName; 1103 } 1104 } 1105