0001 /*
0002 * Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
0003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004 *
0005 * This code is free software; you can redistribute it and/or modify it
0006 * under the terms of the GNU General Public License version 2 only, as
0007 * published by the Free Software Foundation. Sun designates this
0008 * particular file as subject to the "Classpath" exception as provided
0009 * by Sun in the LICENSE file that accompanied this code.
0010 *
0011 * This code is distributed in the hope that it will be useful, but WITHOUT
0012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014 * version 2 for more details (a copy is included in the LICENSE file that
0015 * accompanied this code).
0016 *
0017 * You should have received a copy of the GNU General Public License version
0018 * 2 along with this work; if not, write to the Free Software Foundation,
0019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020 *
0021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022 * CA 95054 USA or visit www.sun.com if you need additional information or
0023 * have any questions.
0024 */
0025 package java.net;
0026
0027 import java.io.IOException;
0028 import java.io.InputStream;
0029 import java.io.OutputStream;
0030 import java.io.BufferedOutputStream;
0031 import java.security.AccessController;
0032 import java.security.PrivilegedExceptionAction;
0033 import java.util.prefs.Preferences;
0034 import sun.net.www.ParseUtil;
0035
0036 /* import org.ietf.jgss.*; */
0037
0038 /**
0039 * SOCKS (V4 & V5) TCP socket implementation (RFC 1928).
0040 * This is a subclass of PlainSocketImpl.
0041 * Note this class should <b>NOT</b> be public.
0042 */
0043
0044 class SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
0045 private String server = null;
0046 private int port = DEFAULT_PORT;
0047 private InetSocketAddress external_address;
0048 private boolean useV4 = false;
0049 private Socket cmdsock = null;
0050 private InputStream cmdIn = null;
0051 private OutputStream cmdOut = null;
0052
0053 SocksSocketImpl() {
0054 // Nothing needed
0055 }
0056
0057 SocksSocketImpl(String server, int port) {
0058 this .server = server;
0059 this .port = (port == -1 ? DEFAULT_PORT : port);
0060 }
0061
0062 SocksSocketImpl(Proxy proxy) {
0063 SocketAddress a = proxy.address();
0064 if (a instanceof InetSocketAddress) {
0065 InetSocketAddress ad = (InetSocketAddress) a;
0066 // Use getHostString() to avoid reverse lookups
0067 server = ad.getHostString();
0068 port = ad.getPort();
0069 }
0070 }
0071
0072 void setV4() {
0073 useV4 = true;
0074 }
0075
0076 private synchronized void privilegedConnect(final String host,
0077 final int port, final int timeout) throws IOException {
0078 try {
0079 AccessController
0080 .doPrivileged(new java.security.PrivilegedExceptionAction() {
0081 public Object run() throws IOException {
0082 super ConnectServer(host, port, timeout);
0083 cmdIn = getInputStream();
0084 cmdOut = getOutputStream();
0085 return null;
0086 }
0087 });
0088 } catch (java.security.PrivilegedActionException pae) {
0089 throw (IOException) pae.getException();
0090 }
0091 }
0092
0093 private void super ConnectServer(String host, int port, int timeout)
0094 throws IOException {
0095 super .connect(new InetSocketAddress(host, port), timeout);
0096 }
0097
0098 private int readSocksReply(InputStream in, byte[] data)
0099 throws IOException {
0100 int len = data.length;
0101 int received = 0;
0102 for (int attempts = 0; received < len && attempts < 3; attempts++) {
0103 int count = in.read(data, received, len - received);
0104 if (count < 0)
0105 throw new SocketException(
0106 "Malformed reply from SOCKS server");
0107 received += count;
0108 }
0109 return received;
0110 }
0111
0112 /**
0113 * Provides the authentication machanism required by the proxy.
0114 */
0115 private boolean authenticate(byte method, InputStream in,
0116 BufferedOutputStream out) throws IOException {
0117 byte[] data = null;
0118 int i;
0119 // No Authentication required. We're done then!
0120 if (method == NO_AUTH)
0121 return true;
0122 /**
0123 * User/Password authentication. Try, in that order :
0124 * - The application provided Authenticator, if any
0125 * - The user preferences java.net.socks.username &
0126 * java.net.socks.password
0127 * - the user.name & no password (backward compatibility behavior).
0128 */
0129 if (method == USER_PASSW) {
0130 String userName;
0131 String password = null;
0132 final InetAddress addr = InetAddress.getByName(server);
0133 PasswordAuthentication pw = (PasswordAuthentication) java.security.AccessController
0134 .doPrivileged(new java.security.PrivilegedAction() {
0135 public Object run() {
0136 return Authenticator
0137 .requestPasswordAuthentication(
0138 server, addr, port,
0139 "SOCKS5",
0140 "SOCKS authentication",
0141 null);
0142 }
0143 });
0144 if (pw != null) {
0145 userName = pw.getUserName();
0146 password = new String(pw.getPassword());
0147 } else {
0148 final Preferences prefs = Preferences.userRoot().node(
0149 "/java/net/socks");
0150 try {
0151 userName = (String) AccessController
0152 .doPrivileged(new java.security.PrivilegedExceptionAction() {
0153 public Object run() throws IOException {
0154 return prefs.get("username", null);
0155 }
0156 });
0157 } catch (java.security.PrivilegedActionException pae) {
0158 throw (IOException) pae.getException();
0159 }
0160
0161 if (userName != null) {
0162 try {
0163 password = (String) AccessController
0164 .doPrivileged(new java.security.PrivilegedExceptionAction() {
0165 public Object run()
0166 throws IOException {
0167 return prefs.get("password",
0168 null);
0169 }
0170 });
0171 } catch (java.security.PrivilegedActionException pae) {
0172 throw (IOException) pae.getException();
0173 }
0174 } else {
0175 userName = (String) java.security.AccessController
0176 .doPrivileged(new sun.security.action.GetPropertyAction(
0177 "user.name"));
0178 }
0179 }
0180 if (userName == null)
0181 return false;
0182 out.write(1);
0183 out.write(userName.length());
0184 try {
0185 out.write(userName.getBytes("ISO-8859-1"));
0186 } catch (java.io.UnsupportedEncodingException uee) {
0187 assert false;
0188 }
0189 if (password != null) {
0190 out.write(password.length());
0191 try {
0192 out.write(password.getBytes("ISO-8859-1"));
0193 } catch (java.io.UnsupportedEncodingException uee) {
0194 assert false;
0195 }
0196 } else
0197 out.write(0);
0198 out.flush();
0199 data = new byte[2];
0200 i = readSocksReply(in, data);
0201 if (i != 2 || data[1] != 0) {
0202 /* RFC 1929 specifies that the connection MUST be closed if
0203 authentication fails */
0204 out.close();
0205 in.close();
0206 return false;
0207 }
0208 /* Authentication succeeded */
0209 return true;
0210 }
0211 /**
0212 * GSSAPI authentication mechanism.
0213 * Unfortunately the RFC seems out of sync with the Reference
0214 * implementation. I'll leave this in for future completion.
0215 */
0216 // if (method == GSSAPI) {
0217 // try {
0218 // GSSManager manager = GSSManager.getInstance();
0219 // GSSName name = manager.createName("SERVICE:socks@"+server,
0220 // null);
0221 // GSSContext context = manager.createContext(name, null, null,
0222 // GSSContext.DEFAULT_LIFETIME);
0223 // context.requestMutualAuth(true);
0224 // context.requestReplayDet(true);
0225 // context.requestSequenceDet(true);
0226 // context.requestCredDeleg(true);
0227 // byte []inToken = new byte[0];
0228 // while (!context.isEstablished()) {
0229 // byte[] outToken
0230 // = context.initSecContext(inToken, 0, inToken.length);
0231 // // send the output token if generated
0232 // if (outToken != null) {
0233 // out.write(1);
0234 // out.write(1);
0235 // out.writeShort(outToken.length);
0236 // out.write(outToken);
0237 // out.flush();
0238 // data = new byte[2];
0239 // i = readSocksReply(in, data);
0240 // if (i != 2 || data[1] == 0xff) {
0241 // in.close();
0242 // out.close();
0243 // return false;
0244 // }
0245 // i = readSocksReply(in, data);
0246 // int len = 0;
0247 // len = ((int)data[0] & 0xff) << 8;
0248 // len += data[1];
0249 // data = new byte[len];
0250 // i = readSocksReply(in, data);
0251 // if (i == len)
0252 // return true;
0253 // in.close();
0254 // out.close();
0255 // }
0256 // }
0257 // } catch (GSSException e) {
0258 // /* RFC 1961 states that if Context initialisation fails the connection
0259 // MUST be closed */
0260 // e.printStackTrace();
0261 // in.close();
0262 // out.close();
0263 // }
0264 // }
0265 return false;
0266 }
0267
0268 private void connectV4(InputStream in, OutputStream out,
0269 InetSocketAddress endpoint) throws IOException {
0270 if (!(endpoint.getAddress() instanceof Inet4Address)) {
0271 throw new SocketException(
0272 "SOCKS V4 requires IPv4 only addresses");
0273 }
0274 out.write(PROTO_VERS4);
0275 out.write(CONNECT);
0276 out.write((endpoint.getPort() >> 8) & 0xff);
0277 out.write((endpoint.getPort() >> 0) & 0xff);
0278 out.write(endpoint.getAddress().getAddress());
0279 String userName = (String) java.security.AccessController
0280 .doPrivileged(new sun.security.action.GetPropertyAction(
0281 "user.name"));
0282 try {
0283 out.write(userName.getBytes("ISO-8859-1"));
0284 } catch (java.io.UnsupportedEncodingException uee) {
0285 assert false;
0286 }
0287 out.write(0);
0288 out.flush();
0289 byte[] data = new byte[8];
0290 int n = readSocksReply(in, data);
0291 if (n != 8)
0292 throw new SocketException(
0293 "Reply from SOCKS server has bad length: " + n);
0294 if (data[0] != 0 && data[0] != 4)
0295 throw new SocketException(
0296 "Reply from SOCKS server has bad version");
0297 SocketException ex = null;
0298 switch (data[1]) {
0299 case 90:
0300 // Success!
0301 external_address = endpoint;
0302 break;
0303 case 91:
0304 ex = new SocketException("SOCKS request rejected");
0305 break;
0306 case 92:
0307 ex = new SocketException(
0308 "SOCKS server couldn't reach destination");
0309 break;
0310 case 93:
0311 ex = new SocketException("SOCKS authentication failed");
0312 break;
0313 default:
0314 ex = new SocketException(
0315 "Reply from SOCKS server contains bad status");
0316 break;
0317 }
0318 if (ex != null) {
0319 in.close();
0320 out.close();
0321 throw ex;
0322 }
0323 }
0324
0325 /**
0326 * Connects the Socks Socket to the specified endpoint. It will first
0327 * connect to the SOCKS proxy and negotiate the access. If the proxy
0328 * grants the connections, then the connect is successful and all
0329 * further traffic will go to the "real" endpoint.
0330 *
0331 * @param endpoint the <code>SocketAddress</code> to connect to.
0332 * @param timeout the timeout value in milliseconds
0333 * @throws IOException if the connection can't be established.
0334 * @throws SecurityException if there is a security manager and it
0335 * doesn't allow the connection
0336 * @throws IllegalArgumentException if endpoint is null or a
0337 * SocketAddress subclass not supported by this socket
0338 */
0339 protected void connect(SocketAddress endpoint, int timeout)
0340 throws IOException {
0341 SecurityManager security = System.getSecurityManager();
0342 if (endpoint == null
0343 || !(endpoint instanceof InetSocketAddress))
0344 throw new IllegalArgumentException(
0345 "Unsupported address type");
0346 InetSocketAddress epoint = (InetSocketAddress) endpoint;
0347 if (security != null) {
0348 if (epoint.isUnresolved())
0349 security.checkConnect(epoint.getHostName(), epoint
0350 .getPort());
0351 else
0352 security.checkConnect(epoint.getAddress()
0353 .getHostAddress(), epoint.getPort());
0354 }
0355 if (server == null) {
0356 // This is the general case
0357 // server is not null only when the socket was created with a
0358 // specified proxy in which case it does bypass the ProxySelector
0359 ProxySelector sel = (ProxySelector) java.security.AccessController
0360 .doPrivileged(new java.security.PrivilegedAction() {
0361 public Object run() {
0362 return ProxySelector.getDefault();
0363 }
0364 });
0365 if (sel == null) {
0366 /*
0367 * No default proxySelector --> direct connection
0368 */
0369 super .connect(epoint, timeout);
0370 return;
0371 }
0372 URI uri = null;
0373 // Use getHostString() to avoid reverse lookups
0374 String host = epoint.getHostString();
0375 // IPv6 litteral?
0376 if (epoint.getAddress() instanceof Inet6Address
0377 && (!host.startsWith("["))
0378 && (host.indexOf(":") >= 0)) {
0379 host = "[" + host + "]";
0380 }
0381 try {
0382 uri = new URI("socket://" + ParseUtil.encodePath(host)
0383 + ":" + epoint.getPort());
0384 } catch (URISyntaxException e) {
0385 // This shouldn't happen
0386 assert false : e;
0387 }
0388 Proxy p = null;
0389 IOException savedExc = null;
0390 java.util.Iterator<Proxy> iProxy = null;
0391 iProxy = sel.select(uri).iterator();
0392 if (iProxy == null || !(iProxy.hasNext())) {
0393 super .connect(epoint, timeout);
0394 return;
0395 }
0396 while (iProxy.hasNext()) {
0397 p = iProxy.next();
0398 if (p == null || p == Proxy.NO_PROXY) {
0399 super .connect(epoint, timeout);
0400 return;
0401 }
0402 if (p.type() != Proxy.Type.SOCKS)
0403 throw new SocketException("Unknown proxy type : "
0404 + p.type());
0405 if (!(p.address() instanceof InetSocketAddress))
0406 throw new SocketException(
0407 "Unknow address type for proxy: " + p);
0408 // Use getHostString() to avoid reverse lookups
0409 server = ((InetSocketAddress) p.address())
0410 .getHostString();
0411 port = ((InetSocketAddress) p.address()).getPort();
0412
0413 // Connects to the SOCKS server
0414 try {
0415 privilegedConnect(server, port, timeout);
0416 // Worked, let's get outta here
0417 break;
0418 } catch (IOException e) {
0419 // Ooops, let's notify the ProxySelector
0420 sel.connectFailed(uri, p.address(), e);
0421 server = null;
0422 port = -1;
0423 savedExc = e;
0424 // Will continue the while loop and try the next proxy
0425 }
0426 }
0427
0428 /*
0429 * If server is still null at this point, none of the proxy
0430 * worked
0431 */
0432 if (server == null) {
0433 throw new SocketException(
0434 "Can't connect to SOCKS proxy:"
0435 + savedExc.getMessage());
0436 }
0437 } else {
0438 // Connects to the SOCKS server
0439 try {
0440 privilegedConnect(server, port, timeout);
0441 } catch (IOException e) {
0442 throw new SocketException(e.getMessage());
0443 }
0444 }
0445
0446 // cmdIn & cmdOut were intialized during the privilegedConnect() call
0447 BufferedOutputStream out = new BufferedOutputStream(cmdOut, 512);
0448 InputStream in = cmdIn;
0449
0450 if (useV4) {
0451 // SOCKS Protocol version 4 doesn't know how to deal with
0452 // DOMAIN type of addresses (unresolved addresses here)
0453 if (epoint.isUnresolved())
0454 throw new UnknownHostException(epoint.toString());
0455 connectV4(in, out, epoint);
0456 return;
0457 }
0458
0459 // This is SOCKS V5
0460 out.write(PROTO_VERS);
0461 out.write(2);
0462 out.write(NO_AUTH);
0463 out.write(USER_PASSW);
0464 out.flush();
0465 byte[] data = new byte[2];
0466 int i = readSocksReply(in, data);
0467 if (i != 2 || ((int) data[0]) != PROTO_VERS) {
0468 // Maybe it's not a V5 sever after all
0469 // Let's try V4 before we give up
0470 // SOCKS Protocol version 4 doesn't know how to deal with
0471 // DOMAIN type of addresses (unresolved addresses here)
0472 if (epoint.isUnresolved())
0473 throw new UnknownHostException(epoint.toString());
0474 connectV4(in, out, epoint);
0475 return;
0476 }
0477 if (((int) data[1]) == NO_METHODS)
0478 throw new SocketException("SOCKS : No acceptable methods");
0479 if (!authenticate(data[1], in, out)) {
0480 throw new SocketException("SOCKS : authentication failed");
0481 }
0482 out.write(PROTO_VERS);
0483 out.write(CONNECT);
0484 out.write(0);
0485 /* Test for IPV4/IPV6/Unresolved */
0486 if (epoint.isUnresolved()) {
0487 out.write(DOMAIN_NAME);
0488 out.write(epoint.getHostName().length());
0489 try {
0490 out.write(epoint.getHostName().getBytes("ISO-8859-1"));
0491 } catch (java.io.UnsupportedEncodingException uee) {
0492 assert false;
0493 }
0494 out.write((epoint.getPort() >> 8) & 0xff);
0495 out.write((epoint.getPort() >> 0) & 0xff);
0496 } else if (epoint.getAddress() instanceof Inet6Address) {
0497 out.write(IPV6);
0498 out.write(epoint.getAddress().getAddress());
0499 out.write((epoint.getPort() >> 8) & 0xff);
0500 out.write((epoint.getPort() >> 0) & 0xff);
0501 } else {
0502 out.write(IPV4);
0503 out.write(epoint.getAddress().getAddress());
0504 out.write((epoint.getPort() >> 8) & 0xff);
0505 out.write((epoint.getPort() >> 0) & 0xff);
0506 }
0507 out.flush();
0508 data = new byte[4];
0509 i = readSocksReply(in, data);
0510 if (i != 4)
0511 throw new SocketException(
0512 "Reply from SOCKS server has bad length");
0513 SocketException ex = null;
0514 int nport, len;
0515 byte[] addr;
0516 switch (data[1]) {
0517 case REQUEST_OK:
0518 // success!
0519 switch (data[3]) {
0520 case IPV4:
0521 addr = new byte[4];
0522 i = readSocksReply(in, addr);
0523 if (i != 4)
0524 throw new SocketException(
0525 "Reply from SOCKS server badly formatted");
0526 data = new byte[2];
0527 i = readSocksReply(in, data);
0528 if (i != 2)
0529 throw new SocketException(
0530 "Reply from SOCKS server badly formatted");
0531 nport = ((int) data[0] & 0xff) << 8;
0532 nport += ((int) data[1] & 0xff);
0533 break;
0534 case DOMAIN_NAME:
0535 len = data[1];
0536 byte[] host = new byte[len];
0537 i = readSocksReply(in, host);
0538 if (i != len)
0539 throw new SocketException(
0540 "Reply from SOCKS server badly formatted");
0541 data = new byte[2];
0542 i = readSocksReply(in, data);
0543 if (i != 2)
0544 throw new SocketException(
0545 "Reply from SOCKS server badly formatted");
0546 nport = ((int) data[0] & 0xff) << 8;
0547 nport += ((int) data[1] & 0xff);
0548 break;
0549 case IPV6:
0550 len = data[1];
0551 addr = new byte[len];
0552 i = readSocksReply(in, addr);
0553 if (i != len)
0554 throw new SocketException(
0555 "Reply from SOCKS server badly formatted");
0556 data = new byte[2];
0557 i = readSocksReply(in, data);
0558 if (i != 2)
0559 throw new SocketException(
0560 "Reply from SOCKS server badly formatted");
0561 nport = ((int) data[0] & 0xff) << 8;
0562 nport += ((int) data[1] & 0xff);
0563 break;
0564 default:
0565 ex = new SocketException(
0566 "Reply from SOCKS server contains wrong code");
0567 break;
0568 }
0569 break;
0570 case GENERAL_FAILURE:
0571 ex = new SocketException("SOCKS server general failure");
0572 break;
0573 case NOT_ALLOWED:
0574 ex = new SocketException(
0575 "SOCKS: Connection not allowed by ruleset");
0576 break;
0577 case NET_UNREACHABLE:
0578 ex = new SocketException("SOCKS: Network unreachable");
0579 break;
0580 case HOST_UNREACHABLE:
0581 ex = new SocketException("SOCKS: Host unreachable");
0582 break;
0583 case CONN_REFUSED:
0584 ex = new SocketException("SOCKS: Connection refused");
0585 break;
0586 case TTL_EXPIRED:
0587 ex = new SocketException("SOCKS: TTL expired");
0588 break;
0589 case CMD_NOT_SUPPORTED:
0590 ex = new SocketException("SOCKS: Command not supported");
0591 break;
0592 case ADDR_TYPE_NOT_SUP:
0593 ex = new SocketException(
0594 "SOCKS: address type not supported");
0595 break;
0596 }
0597 if (ex != null) {
0598 in.close();
0599 out.close();
0600 throw ex;
0601 }
0602 external_address = epoint;
0603 }
0604
0605 private void bindV4(InputStream in, OutputStream out,
0606 InetAddress baddr, int lport) throws IOException {
0607 if (!(baddr instanceof Inet4Address)) {
0608 throw new SocketException(
0609 "SOCKS V4 requires IPv4 only addresses");
0610 }
0611 super .bind(baddr, lport);
0612 byte[] addr1 = baddr.getAddress();
0613 /* Test for AnyLocal */
0614 InetAddress naddr = baddr;
0615 if (naddr.isAnyLocalAddress()) {
0616 naddr = cmdsock.getLocalAddress();
0617 addr1 = naddr.getAddress();
0618 }
0619 out.write(PROTO_VERS4);
0620 out.write(BIND);
0621 out.write((super .getLocalPort() >> 8) & 0xff);
0622 out.write((super .getLocalPort() >> 0) & 0xff);
0623 out.write(addr1);
0624 String userName = (String) java.security.AccessController
0625 .doPrivileged(new sun.security.action.GetPropertyAction(
0626 "user.name"));
0627 try {
0628 out.write(userName.getBytes("ISO-8859-1"));
0629 } catch (java.io.UnsupportedEncodingException uee) {
0630 assert false;
0631 }
0632 out.write(0);
0633 out.flush();
0634 byte[] data = new byte[8];
0635 int n = readSocksReply(in, data);
0636 if (n != 8)
0637 throw new SocketException(
0638 "Reply from SOCKS server has bad length: " + n);
0639 if (data[0] != 0 && data[0] != 4)
0640 throw new SocketException(
0641 "Reply from SOCKS server has bad version");
0642 SocketException ex = null;
0643 switch (data[1]) {
0644 case 90:
0645 // Success!
0646 external_address = new InetSocketAddress(baddr, lport);
0647 break;
0648 case 91:
0649 ex = new SocketException("SOCKS request rejected");
0650 break;
0651 case 92:
0652 ex = new SocketException(
0653 "SOCKS server couldn't reach destination");
0654 break;
0655 case 93:
0656 ex = new SocketException("SOCKS authentication failed");
0657 break;
0658 default:
0659 ex = new SocketException(
0660 "Reply from SOCKS server contains bad status");
0661 break;
0662 }
0663 if (ex != null) {
0664 in.close();
0665 out.close();
0666 throw ex;
0667 }
0668
0669 }
0670
0671 /**
0672 * Sends the Bind request to the SOCKS proxy. In the SOCKS protocol, bind
0673 * means "accept incoming connection from", so the SocketAddress is the
0674 * the one of the host we do accept connection from.
0675 *
0676 * @param addr the Socket address of the remote host.
0677 * @exception IOException if an I/O error occurs when binding this socket.
0678 */
0679 protected synchronized void socksBind(InetSocketAddress saddr)
0680 throws IOException {
0681 if (socket != null) {
0682 // this is a client socket, not a server socket, don't
0683 // call the SOCKS proxy for a bind!
0684 return;
0685 }
0686
0687 // Connects to the SOCKS server
0688
0689 if (server == null) {
0690 // This is the general case
0691 // server is not null only when the socket was created with a
0692 // specified proxy in which case it does bypass the ProxySelector
0693 ProxySelector sel = (ProxySelector) java.security.AccessController
0694 .doPrivileged(new java.security.PrivilegedAction() {
0695 public Object run() {
0696 return ProxySelector.getDefault();
0697 }
0698 });
0699 if (sel == null) {
0700 /*
0701 * No default proxySelector --> direct connection
0702 */
0703 return;
0704 }
0705 URI uri = null;
0706 // Use getHostString() to avoid reverse lookups
0707 String host = saddr.getHostString();
0708 // IPv6 litteral?
0709 if (saddr.getAddress() instanceof Inet6Address
0710 && (!host.startsWith("["))
0711 && (host.indexOf(":") >= 0)) {
0712 host = "[" + host + "]";
0713 }
0714 try {
0715 uri = new URI("serversocket://"
0716 + ParseUtil.encodePath(host) + ":"
0717 + saddr.getPort());
0718 } catch (URISyntaxException e) {
0719 // This shouldn't happen
0720 assert false : e;
0721 }
0722 Proxy p = null;
0723 Exception savedExc = null;
0724 java.util.Iterator<Proxy> iProxy = null;
0725 iProxy = sel.select(uri).iterator();
0726 if (iProxy == null || !(iProxy.hasNext())) {
0727 return;
0728 }
0729 while (iProxy.hasNext()) {
0730 p = iProxy.next();
0731 if (p == null || p == Proxy.NO_PROXY) {
0732 return;
0733 }
0734 if (p.type() != Proxy.Type.SOCKS)
0735 throw new SocketException("Unknown proxy type : "
0736 + p.type());
0737 if (!(p.address() instanceof InetSocketAddress))
0738 throw new SocketException(
0739 "Unknow address type for proxy: " + p);
0740 // Use getHostString() to avoid reverse lookups
0741 server = ((InetSocketAddress) p.address())
0742 .getHostString();
0743 port = ((InetSocketAddress) p.address()).getPort();
0744
0745 // Connects to the SOCKS server
0746 try {
0747 AccessController
0748 .doPrivileged(new PrivilegedExceptionAction() {
0749 public Object run() throws Exception {
0750 cmdsock = new Socket(
0751 new PlainSocketImpl());
0752 cmdsock
0753 .connect(new InetSocketAddress(
0754 server, port));
0755 cmdIn = cmdsock.getInputStream();
0756 cmdOut = cmdsock.getOutputStream();
0757 return null;
0758 }
0759 });
0760 } catch (Exception e) {
0761 // Ooops, let's notify the ProxySelector
0762 sel.connectFailed(uri, p.address(),
0763 new SocketException(e.getMessage()));
0764 server = null;
0765 port = -1;
0766 cmdsock = null;
0767 savedExc = e;
0768 // Will continue the while loop and try the next proxy
0769 }
0770 }
0771
0772 /*
0773 * If server is still null at this point, none of the proxy
0774 * worked
0775 */
0776 if (server == null || cmdsock == null) {
0777 throw new SocketException(
0778 "Can't connect to SOCKS proxy:"
0779 + savedExc.getMessage());
0780 }
0781 } else {
0782 try {
0783 AccessController
0784 .doPrivileged(new PrivilegedExceptionAction() {
0785 public Object run() throws Exception {
0786 cmdsock = new Socket(
0787 new PlainSocketImpl());
0788 cmdsock.connect(new InetSocketAddress(
0789 server, port));
0790 cmdIn = cmdsock.getInputStream();
0791 cmdOut = cmdsock.getOutputStream();
0792 return null;
0793 }
0794 });
0795 } catch (Exception e) {
0796 throw new SocketException(e.getMessage());
0797 }
0798 }
0799 BufferedOutputStream out = new BufferedOutputStream(cmdOut, 512);
0800 InputStream in = cmdIn;
0801 if (useV4) {
0802 bindV4(in, out, saddr.getAddress(), saddr.getPort());
0803 return;
0804 }
0805 out.write(PROTO_VERS);
0806 out.write(2);
0807 out.write(NO_AUTH);
0808 out.write(USER_PASSW);
0809 out.flush();
0810 byte[] data = new byte[2];
0811 int i = readSocksReply(in, data);
0812 if (i != 2 || ((int) data[0]) != PROTO_VERS) {
0813 // Maybe it's not a V5 sever after all
0814 // Let's try V4 before we give up
0815 bindV4(in, out, saddr.getAddress(), saddr.getPort());
0816 return;
0817 }
0818 if (((int) data[1]) == NO_METHODS)
0819 throw new SocketException("SOCKS : No acceptable methods");
0820 if (!authenticate(data[1], in, out)) {
0821 throw new SocketException("SOCKS : authentication failed");
0822 }
0823 // We're OK. Let's issue the BIND command.
0824 out.write(PROTO_VERS);
0825 out.write(BIND);
0826 out.write(0);
0827 int lport = saddr.getPort();
0828 if (saddr.isUnresolved()) {
0829 out.write(DOMAIN_NAME);
0830 out.write(saddr.getHostName().length());
0831 try {
0832 out.write(saddr.getHostName().getBytes("ISO-8859-1"));
0833 } catch (java.io.UnsupportedEncodingException uee) {
0834 assert false;
0835 }
0836 out.write((lport >> 8) & 0xff);
0837 out.write((lport >> 0) & 0xff);
0838 } else if (saddr.getAddress() instanceof Inet4Address) {
0839 byte[] addr1 = saddr.getAddress().getAddress();
0840 out.write(IPV4);
0841 out.write(addr1);
0842 out.write((lport >> 8) & 0xff);
0843 out.write((lport >> 0) & 0xff);
0844 out.flush();
0845 } else if (saddr.getAddress() instanceof Inet6Address) {
0846 byte[] addr1 = saddr.getAddress().getAddress();
0847 out.write(IPV6);
0848 out.write(addr1);
0849 out.write((lport >> 8) & 0xff);
0850 out.write((lport >> 0) & 0xff);
0851 out.flush();
0852 } else {
0853 cmdsock.close();
0854 throw new SocketException("unsupported address type : "
0855 + saddr);
0856 }
0857 data = new byte[4];
0858 i = readSocksReply(in, data);
0859 SocketException ex = null;
0860 int len, nport;
0861 byte[] addr;
0862 switch (data[1]) {
0863 case REQUEST_OK:
0864 // success!
0865 InetSocketAddress real_end = null;
0866 switch (data[3]) {
0867 case IPV4:
0868 addr = new byte[4];
0869 i = readSocksReply(in, addr);
0870 if (i != 4)
0871 throw new SocketException(
0872 "Reply from SOCKS server badly formatted");
0873 data = new byte[2];
0874 i = readSocksReply(in, data);
0875 if (i != 2)
0876 throw new SocketException(
0877 "Reply from SOCKS server badly formatted");
0878 nport = ((int) data[0] & 0xff) << 8;
0879 nport += ((int) data[1] & 0xff);
0880 external_address = new InetSocketAddress(
0881 new Inet4Address("", addr), nport);
0882 break;
0883 case DOMAIN_NAME:
0884 len = data[1];
0885 byte[] host = new byte[len];
0886 i = readSocksReply(in, host);
0887 if (i != len)
0888 throw new SocketException(
0889 "Reply from SOCKS server badly formatted");
0890 data = new byte[2];
0891 i = readSocksReply(in, data);
0892 if (i != 2)
0893 throw new SocketException(
0894 "Reply from SOCKS server badly formatted");
0895 nport = ((int) data[0] & 0xff) << 8;
0896 nport += ((int) data[1] & 0xff);
0897 external_address = new InetSocketAddress(new String(
0898 host), nport);
0899 break;
0900 case IPV6:
0901 len = data[1];
0902 addr = new byte[len];
0903 i = readSocksReply(in, addr);
0904 if (i != len)
0905 throw new SocketException(
0906 "Reply from SOCKS server badly formatted");
0907 data = new byte[2];
0908 i = readSocksReply(in, data);
0909 if (i != 2)
0910 throw new SocketException(
0911 "Reply from SOCKS server badly formatted");
0912 nport = ((int) data[0] & 0xff) << 8;
0913 nport += ((int) data[1] & 0xff);
0914 external_address = new InetSocketAddress(
0915 new Inet6Address("", addr), nport);
0916 break;
0917 }
0918 break;
0919 case GENERAL_FAILURE:
0920 ex = new SocketException("SOCKS server general failure");
0921 break;
0922 case NOT_ALLOWED:
0923 ex = new SocketException(
0924 "SOCKS: Bind not allowed by ruleset");
0925 break;
0926 case NET_UNREACHABLE:
0927 ex = new SocketException("SOCKS: Network unreachable");
0928 break;
0929 case HOST_UNREACHABLE:
0930 ex = new SocketException("SOCKS: Host unreachable");
0931 break;
0932 case CONN_REFUSED:
0933 ex = new SocketException("SOCKS: Connection refused");
0934 break;
0935 case TTL_EXPIRED:
0936 ex = new SocketException("SOCKS: TTL expired");
0937 break;
0938 case CMD_NOT_SUPPORTED:
0939 ex = new SocketException("SOCKS: Command not supported");
0940 break;
0941 case ADDR_TYPE_NOT_SUP:
0942 ex = new SocketException(
0943 "SOCKS: address type not supported");
0944 break;
0945 }
0946 if (ex != null) {
0947 in.close();
0948 out.close();
0949 cmdsock.close();
0950 cmdsock = null;
0951 throw ex;
0952 }
0953 cmdIn = in;
0954 cmdOut = out;
0955 }
0956
0957 /**
0958 * Accepts a connection from a specific host.
0959 *
0960 * @param s the accepted connection.
0961 * @param saddr the socket address of the host we do accept
0962 * connection from
0963 * @exception IOException if an I/O error occurs when accepting the
0964 * connection.
0965 */
0966 protected void acceptFrom(SocketImpl s, InetSocketAddress saddr)
0967 throws IOException {
0968 if (cmdsock == null) {
0969 // Not a Socks ServerSocket.
0970 return;
0971 }
0972 InputStream in = cmdIn;
0973 // Sends the "SOCKS BIND" request.
0974 socksBind(saddr);
0975 in.read();
0976 int i = in.read();
0977 in.read();
0978 SocketException ex = null;
0979 int nport;
0980 byte[] addr;
0981 InetSocketAddress real_end = null;
0982 switch (i) {
0983 case REQUEST_OK:
0984 // success!
0985 i = in.read();
0986 switch (i) {
0987 case IPV4:
0988 addr = new byte[4];
0989 readSocksReply(in, addr);
0990 nport = in.read() << 8;
0991 nport += in.read();
0992 real_end = new InetSocketAddress(new Inet4Address("",
0993 addr), nport);
0994 break;
0995 case DOMAIN_NAME:
0996 int len = in.read();
0997 addr = new byte[len];
0998 readSocksReply(in, addr);
0999 nport = in.read() << 8;
1000 nport += in.read();
1001 real_end = new InetSocketAddress(new String(addr),
1002 nport);
1003 break;
1004 case IPV6:
1005 addr = new byte[16];
1006 readSocksReply(in, addr);
1007 nport = in.read() << 8;
1008 nport += in.read();
1009 real_end = new InetSocketAddress(new Inet6Address("",
1010 addr), nport);
1011 break;
1012 }
1013 break;
1014 case GENERAL_FAILURE:
1015 ex = new SocketException("SOCKS server general failure");
1016 break;
1017 case NOT_ALLOWED:
1018 ex = new SocketException(
1019 "SOCKS: Accept not allowed by ruleset");
1020 break;
1021 case NET_UNREACHABLE:
1022 ex = new SocketException("SOCKS: Network unreachable");
1023 break;
1024 case HOST_UNREACHABLE:
1025 ex = new SocketException("SOCKS: Host unreachable");
1026 break;
1027 case CONN_REFUSED:
1028 ex = new SocketException("SOCKS: Connection refused");
1029 break;
1030 case TTL_EXPIRED:
1031 ex = new SocketException("SOCKS: TTL expired");
1032 break;
1033 case CMD_NOT_SUPPORTED:
1034 ex = new SocketException("SOCKS: Command not supported");
1035 break;
1036 case ADDR_TYPE_NOT_SUP:
1037 ex = new SocketException(
1038 "SOCKS: address type not supported");
1039 break;
1040 }
1041 if (ex != null) {
1042 cmdIn.close();
1043 cmdOut.close();
1044 cmdsock.close();
1045 cmdsock = null;
1046 throw ex;
1047 }
1048
1049 /**
1050 * This is where we have to do some fancy stuff.
1051 * The datastream from the socket "accepted" by the proxy will
1052 * come through the cmdSocket. So we have to swap the socketImpls
1053 */
1054 if (s instanceof SocksSocketImpl) {
1055 ((SocksSocketImpl) s).external_address = real_end;
1056 }
1057 if (s instanceof PlainSocketImpl) {
1058 PlainSocketImpl psi = (PlainSocketImpl) s;
1059 psi.setInputStream((SocketInputStream) in);
1060 psi
1061 .setFileDescriptor(cmdsock.getImpl()
1062 .getFileDescriptor());
1063 psi.setAddress(cmdsock.getImpl().getInetAddress());
1064 psi.setPort(cmdsock.getImpl().getPort());
1065 psi.setLocalPort(cmdsock.getImpl().getLocalPort());
1066 } else {
1067 s.fd = cmdsock.getImpl().fd;
1068 s.address = cmdsock.getImpl().address;
1069 s.port = cmdsock.getImpl().port;
1070 s.localport = cmdsock.getImpl().localport;
1071 }
1072
1073 // Need to do that so that the socket won't be closed
1074 // when the ServerSocket is closed by the user.
1075 // It kinds of detaches the Socket because it is now
1076 // used elsewhere.
1077 cmdsock = null;
1078 }
1079
1080 /**
1081 * Returns the value of this socket's <code>address</code> field.
1082 *
1083 * @return the value of this socket's <code>address</code> field.
1084 * @see java.net.SocketImpl#address
1085 */
1086 protected InetAddress getInetAddress() {
1087 if (external_address != null)
1088 return external_address.getAddress();
1089 else
1090 return super .getInetAddress();
1091 }
1092
1093 /**
1094 * Returns the value of this socket's <code>port</code> field.
1095 *
1096 * @return the value of this socket's <code>port</code> field.
1097 * @see java.net.SocketImpl#port
1098 */
1099 protected int getPort() {
1100 if (external_address != null)
1101 return external_address.getPort();
1102 else
1103 return super .getPort();
1104 }
1105
1106 protected int getLocalPort() {
1107 if (socket != null)
1108 return super .getLocalPort();
1109 if (external_address != null)
1110 return external_address.getPort();
1111 else
1112 return super .getLocalPort();
1113 }
1114
1115 protected void close() throws IOException {
1116 if (cmdsock != null)
1117 cmdsock.close();
1118 cmdsock = null;
1119 super.close();
1120 }
1121
1122 }
|