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