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