0N/A/*
3393N/A * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/Apackage java.net;
0N/Aimport java.io.IOException;
0N/Aimport java.io.InputStream;
0N/Aimport java.io.OutputStream;
0N/Aimport java.io.BufferedOutputStream;
0N/Aimport java.security.AccessController;
6319N/Aimport java.security.PrivilegedAction;
0N/Aimport java.security.PrivilegedExceptionAction;
3393N/Aimport sun.net.SocksProxy;
0N/Aimport sun.net.www.ParseUtil;
0N/A/* import org.ietf.jgss.*; */
0N/A
0N/A/**
0N/A * SOCKS (V4 & V5) TCP socket implementation (RFC 1928).
0N/A * This is a subclass of PlainSocketImpl.
0N/A * Note this class should <b>NOT</b> be public.
0N/A */
0N/A
0N/Aclass SocksSocketImpl extends PlainSocketImpl implements SocksConsts {
0N/A private String server = null;
1305N/A private int serverPort = DEFAULT_PORT;
0N/A private InetSocketAddress external_address;
0N/A private boolean useV4 = false;
0N/A private Socket cmdsock = null;
0N/A private InputStream cmdIn = null;
0N/A private OutputStream cmdOut = null;
1503N/A /* true if the Proxy has been set programatically */
1503N/A private boolean applicationSetProxy; /* false */
1503N/A
0N/A
0N/A SocksSocketImpl() {
0N/A // Nothing needed
0N/A }
0N/A
0N/A SocksSocketImpl(String server, int port) {
0N/A this.server = server;
1305N/A this.serverPort = (port == -1 ? DEFAULT_PORT : port);
0N/A }
0N/A
0N/A SocksSocketImpl(Proxy proxy) {
0N/A SocketAddress a = proxy.address();
0N/A if (a instanceof InetSocketAddress) {
0N/A InetSocketAddress ad = (InetSocketAddress) a;
0N/A // Use getHostString() to avoid reverse lookups
0N/A server = ad.getHostString();
1305N/A serverPort = ad.getPort();
0N/A }
0N/A }
0N/A
0N/A void setV4() {
0N/A useV4 = true;
0N/A }
0N/A
0N/A private synchronized void privilegedConnect(final String host,
0N/A final int port,
0N/A final int timeout)
0N/A throws IOException
0N/A {
0N/A try {
0N/A AccessController.doPrivileged(
28N/A new java.security.PrivilegedExceptionAction<Void>() {
28N/A public Void run() throws IOException {
0N/A superConnectServer(host, port, timeout);
0N/A cmdIn = getInputStream();
0N/A cmdOut = getOutputStream();
0N/A return null;
0N/A }
0N/A });
0N/A } catch (java.security.PrivilegedActionException pae) {
0N/A throw (IOException) pae.getException();
0N/A }
0N/A }
0N/A
0N/A private void superConnectServer(String host, int port,
0N/A int timeout) throws IOException {
0N/A super.connect(new InetSocketAddress(host, port), timeout);
0N/A }
0N/A
2226N/A private static int remainingMillis(long deadlineMillis) throws IOException {
2226N/A if (deadlineMillis == 0L)
2226N/A return 0;
2226N/A
2226N/A final long remaining = deadlineMillis - System.currentTimeMillis();
2226N/A if (remaining > 0)
2226N/A return (int) remaining;
2226N/A
2226N/A throw new SocketTimeoutException();
2226N/A }
2226N/A
0N/A private int readSocksReply(InputStream in, byte[] data) throws IOException {
2226N/A return readSocksReply(in, data, 0L);
2226N/A }
2226N/A
2226N/A private int readSocksReply(InputStream in, byte[] data, long deadlineMillis) throws IOException {
0N/A int len = data.length;
0N/A int received = 0;
0N/A for (int attempts = 0; received < len && attempts < 3; attempts++) {
2226N/A int count;
2226N/A try {
2226N/A count = ((SocketInputStream)in).read(data, received, len - received, remainingMillis(deadlineMillis));
2226N/A } catch (SocketTimeoutException e) {
2226N/A throw new SocketTimeoutException("Connect timed out");
2226N/A }
0N/A if (count < 0)
0N/A throw new SocketException("Malformed reply from SOCKS server");
0N/A received += count;
0N/A }
0N/A return received;
0N/A }
0N/A
0N/A /**
0N/A * Provides the authentication machanism required by the proxy.
0N/A */
0N/A private boolean authenticate(byte method, InputStream in,
0N/A BufferedOutputStream out) throws IOException {
2226N/A return authenticate(method, in, out, 0L);
2226N/A }
2226N/A
2226N/A private boolean authenticate(byte method, InputStream in,
2226N/A BufferedOutputStream out,
2226N/A long deadlineMillis) throws IOException {
0N/A // No Authentication required. We're done then!
0N/A if (method == NO_AUTH)
0N/A return true;
0N/A /**
0N/A * User/Password authentication. Try, in that order :
0N/A * - The application provided Authenticator, if any
0N/A * - the user.name & no password (backward compatibility behavior).
0N/A */
0N/A if (method == USER_PASSW) {
0N/A String userName;
0N/A String password = null;
0N/A final InetAddress addr = InetAddress.getByName(server);
28N/A PasswordAuthentication pw =
0N/A java.security.AccessController.doPrivileged(
28N/A new java.security.PrivilegedAction<PasswordAuthentication>() {
28N/A public PasswordAuthentication run() {
0N/A return Authenticator.requestPasswordAuthentication(
1305N/A server, addr, serverPort, "SOCKS5", "SOCKS authentication", null);
0N/A }
0N/A });
0N/A if (pw != null) {
0N/A userName = pw.getUserName();
0N/A password = new String(pw.getPassword());
0N/A } else {
1305N/A userName = java.security.AccessController.doPrivileged(
0N/A new sun.security.action.GetPropertyAction("user.name"));
0N/A }
0N/A if (userName == null)
0N/A return false;
0N/A out.write(1);
0N/A out.write(userName.length());
0N/A try {
0N/A out.write(userName.getBytes("ISO-8859-1"));
0N/A } catch (java.io.UnsupportedEncodingException uee) {
0N/A assert false;
0N/A }
0N/A if (password != null) {
0N/A out.write(password.length());
0N/A try {
0N/A out.write(password.getBytes("ISO-8859-1"));
0N/A } catch (java.io.UnsupportedEncodingException uee) {
0N/A assert false;
0N/A }
0N/A } else
0N/A out.write(0);
0N/A out.flush();
1305N/A byte[] data = new byte[2];
2226N/A int i = readSocksReply(in, data, deadlineMillis);
0N/A if (i != 2 || data[1] != 0) {
0N/A /* RFC 1929 specifies that the connection MUST be closed if
0N/A authentication fails */
0N/A out.close();
0N/A in.close();
0N/A return false;
0N/A }
0N/A /* Authentication succeeded */
0N/A return true;
0N/A }
0N/A /**
0N/A * GSSAPI authentication mechanism.
0N/A * Unfortunately the RFC seems out of sync with the Reference
0N/A * implementation. I'll leave this in for future completion.
0N/A */
0N/A// if (method == GSSAPI) {
0N/A// try {
0N/A// GSSManager manager = GSSManager.getInstance();
0N/A// GSSName name = manager.createName("SERVICE:socks@"+server,
0N/A// null);
0N/A// GSSContext context = manager.createContext(name, null, null,
0N/A// GSSContext.DEFAULT_LIFETIME);
0N/A// context.requestMutualAuth(true);
0N/A// context.requestReplayDet(true);
0N/A// context.requestSequenceDet(true);
0N/A// context.requestCredDeleg(true);
0N/A// byte []inToken = new byte[0];
0N/A// while (!context.isEstablished()) {
0N/A// byte[] outToken
0N/A// = context.initSecContext(inToken, 0, inToken.length);
0N/A// // send the output token if generated
0N/A// if (outToken != null) {
0N/A// out.write(1);
0N/A// out.write(1);
0N/A// out.writeShort(outToken.length);
0N/A// out.write(outToken);
0N/A// out.flush();
0N/A// data = new byte[2];
2226N/A// i = readSocksReply(in, data, deadlineMillis);
0N/A// if (i != 2 || data[1] == 0xff) {
0N/A// in.close();
0N/A// out.close();
0N/A// return false;
0N/A// }
2226N/A// i = readSocksReply(in, data, deadlineMillis);
0N/A// int len = 0;
0N/A// len = ((int)data[0] & 0xff) << 8;
0N/A// len += data[1];
0N/A// data = new byte[len];
2226N/A// i = readSocksReply(in, data, deadlineMillis);
0N/A// if (i == len)
0N/A// return true;
0N/A// in.close();
0N/A// out.close();
0N/A// }
0N/A// }
0N/A// } catch (GSSException e) {
0N/A// /* RFC 1961 states that if Context initialisation fails the connection
0N/A// MUST be closed */
0N/A// e.printStackTrace();
0N/A// in.close();
0N/A// out.close();
0N/A// }
0N/A// }
0N/A return false;
0N/A }
0N/A
0N/A private void connectV4(InputStream in, OutputStream out,
2226N/A InetSocketAddress endpoint,
2226N/A long deadlineMillis) throws IOException {
0N/A if (!(endpoint.getAddress() instanceof Inet4Address)) {
0N/A throw new SocketException("SOCKS V4 requires IPv4 only addresses");
0N/A }
0N/A out.write(PROTO_VERS4);
0N/A out.write(CONNECT);
0N/A out.write((endpoint.getPort() >> 8) & 0xff);
0N/A out.write((endpoint.getPort() >> 0) & 0xff);
0N/A out.write(endpoint.getAddress().getAddress());
1503N/A String userName = getUserName();
0N/A try {
0N/A out.write(userName.getBytes("ISO-8859-1"));
0N/A } catch (java.io.UnsupportedEncodingException uee) {
0N/A assert false;
0N/A }
0N/A out.write(0);
0N/A out.flush();
0N/A byte[] data = new byte[8];
2226N/A int n = readSocksReply(in, data, deadlineMillis);
0N/A if (n != 8)
0N/A throw new SocketException("Reply from SOCKS server has bad length: " + n);
0N/A if (data[0] != 0 && data[0] != 4)
0N/A throw new SocketException("Reply from SOCKS server has bad version");
0N/A SocketException ex = null;
0N/A switch (data[1]) {
0N/A case 90:
0N/A // Success!
0N/A external_address = endpoint;
0N/A break;
0N/A case 91:
0N/A ex = new SocketException("SOCKS request rejected");
0N/A break;
0N/A case 92:
0N/A ex = new SocketException("SOCKS server couldn't reach destination");
0N/A break;
0N/A case 93:
0N/A ex = new SocketException("SOCKS authentication failed");
0N/A break;
0N/A default:
0N/A ex = new SocketException("Reply from SOCKS server contains bad status");
0N/A break;
0N/A }
0N/A if (ex != null) {
0N/A in.close();
0N/A out.close();
0N/A throw ex;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Connects the Socks Socket to the specified endpoint. It will first
0N/A * connect to the SOCKS proxy and negotiate the access. If the proxy
0N/A * grants the connections, then the connect is successful and all
0N/A * further traffic will go to the "real" endpoint.
0N/A *
0N/A * @param endpoint the <code>SocketAddress</code> to connect to.
0N/A * @param timeout the timeout value in milliseconds
0N/A * @throws IOException if the connection can't be established.
0N/A * @throws SecurityException if there is a security manager and it
0N/A * doesn't allow the connection
0N/A * @throws IllegalArgumentException if endpoint is null or a
0N/A * SocketAddress subclass not supported by this socket
0N/A */
1305N/A @Override
0N/A protected void connect(SocketAddress endpoint, int timeout) throws IOException {
2226N/A final long deadlineMillis;
2226N/A
2226N/A if (timeout == 0) {
2226N/A deadlineMillis = 0L;
2226N/A } else {
2226N/A long finish = System.currentTimeMillis() + timeout;
2226N/A deadlineMillis = finish < 0 ? Long.MAX_VALUE : finish;
2226N/A }
2226N/A
0N/A SecurityManager security = System.getSecurityManager();
0N/A if (endpoint == null || !(endpoint instanceof InetSocketAddress))
0N/A throw new IllegalArgumentException("Unsupported address type");
0N/A InetSocketAddress epoint = (InetSocketAddress) endpoint;
0N/A if (security != null) {
0N/A if (epoint.isUnresolved())
0N/A security.checkConnect(epoint.getHostName(),
0N/A epoint.getPort());
0N/A else
0N/A security.checkConnect(epoint.getAddress().getHostAddress(),
0N/A epoint.getPort());
0N/A }
0N/A if (server == null) {
0N/A // This is the general case
0N/A // server is not null only when the socket was created with a
0N/A // specified proxy in which case it does bypass the ProxySelector
28N/A ProxySelector sel = java.security.AccessController.doPrivileged(
28N/A new java.security.PrivilegedAction<ProxySelector>() {
28N/A public ProxySelector run() {
0N/A return ProxySelector.getDefault();
0N/A }
0N/A });
0N/A if (sel == null) {
0N/A /*
0N/A * No default proxySelector --> direct connection
0N/A */
2226N/A super.connect(epoint, remainingMillis(deadlineMillis));
0N/A return;
0N/A }
1305N/A URI uri;
0N/A // Use getHostString() to avoid reverse lookups
0N/A String host = epoint.getHostString();
0N/A // IPv6 litteral?
0N/A if (epoint.getAddress() instanceof Inet6Address &&
0N/A (!host.startsWith("[")) && (host.indexOf(":") >= 0)) {
0N/A host = "[" + host + "]";
0N/A }
0N/A try {
0N/A uri = new URI("socket://" + ParseUtil.encodePath(host) + ":"+ epoint.getPort());
0N/A } catch (URISyntaxException e) {
0N/A // This shouldn't happen
0N/A assert false : e;
1305N/A uri = null;
0N/A }
0N/A Proxy p = null;
0N/A IOException savedExc = null;
0N/A java.util.Iterator<Proxy> iProxy = null;
0N/A iProxy = sel.select(uri).iterator();
0N/A if (iProxy == null || !(iProxy.hasNext())) {
2226N/A super.connect(epoint, remainingMillis(deadlineMillis));
0N/A return;
0N/A }
0N/A while (iProxy.hasNext()) {
0N/A p = iProxy.next();
0N/A if (p == null || p == Proxy.NO_PROXY) {
2226N/A super.connect(epoint, remainingMillis(deadlineMillis));
0N/A return;
0N/A }
0N/A if (p.type() != Proxy.Type.SOCKS)
0N/A throw new SocketException("Unknown proxy type : " + p.type());
0N/A if (!(p.address() instanceof InetSocketAddress))
0N/A throw new SocketException("Unknow address type for proxy: " + p);
0N/A // Use getHostString() to avoid reverse lookups
0N/A server = ((InetSocketAddress) p.address()).getHostString();
1305N/A serverPort = ((InetSocketAddress) p.address()).getPort();
3393N/A if (p instanceof SocksProxy) {
3393N/A if (((SocksProxy)p).protocolVersion() == 4) {
3393N/A useV4 = true;
3393N/A }
3393N/A }
0N/A
0N/A // Connects to the SOCKS server
0N/A try {
2226N/A privilegedConnect(server, serverPort, remainingMillis(deadlineMillis));
0N/A // Worked, let's get outta here
0N/A break;
0N/A } catch (IOException e) {
0N/A // Ooops, let's notify the ProxySelector
0N/A sel.connectFailed(uri,p.address(),e);
0N/A server = null;
1305N/A serverPort = -1;
0N/A savedExc = e;
0N/A // Will continue the while loop and try the next proxy
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * If server is still null at this point, none of the proxy
0N/A * worked
0N/A */
0N/A if (server == null) {
0N/A throw new SocketException("Can't connect to SOCKS proxy:"
0N/A + savedExc.getMessage());
0N/A }
0N/A } else {
0N/A // Connects to the SOCKS server
0N/A try {
2226N/A privilegedConnect(server, serverPort, remainingMillis(deadlineMillis));
0N/A } catch (IOException e) {
0N/A throw new SocketException(e.getMessage());
0N/A }
0N/A }
0N/A
0N/A // cmdIn & cmdOut were intialized during the privilegedConnect() call
0N/A BufferedOutputStream out = new BufferedOutputStream(cmdOut, 512);
0N/A InputStream in = cmdIn;
0N/A
0N/A if (useV4) {
0N/A // SOCKS Protocol version 4 doesn't know how to deal with
0N/A // DOMAIN type of addresses (unresolved addresses here)
0N/A if (epoint.isUnresolved())
0N/A throw new UnknownHostException(epoint.toString());
2226N/A connectV4(in, out, epoint, deadlineMillis);
0N/A return;
0N/A }
0N/A
0N/A // This is SOCKS V5
0N/A out.write(PROTO_VERS);
0N/A out.write(2);
0N/A out.write(NO_AUTH);
0N/A out.write(USER_PASSW);
0N/A out.flush();
0N/A byte[] data = new byte[2];
2226N/A int i = readSocksReply(in, data, deadlineMillis);
0N/A if (i != 2 || ((int)data[0]) != PROTO_VERS) {
0N/A // Maybe it's not a V5 sever after all
0N/A // Let's try V4 before we give up
0N/A // SOCKS Protocol version 4 doesn't know how to deal with
0N/A // DOMAIN type of addresses (unresolved addresses here)
0N/A if (epoint.isUnresolved())
0N/A throw new UnknownHostException(epoint.toString());
2226N/A connectV4(in, out, epoint, deadlineMillis);
0N/A return;
0N/A }
0N/A if (((int)data[1]) == NO_METHODS)
0N/A throw new SocketException("SOCKS : No acceptable methods");
2226N/A if (!authenticate(data[1], in, out, deadlineMillis)) {
0N/A throw new SocketException("SOCKS : authentication failed");
0N/A }
0N/A out.write(PROTO_VERS);
0N/A out.write(CONNECT);
0N/A out.write(0);
0N/A /* Test for IPV4/IPV6/Unresolved */
0N/A if (epoint.isUnresolved()) {
0N/A out.write(DOMAIN_NAME);
0N/A out.write(epoint.getHostName().length());
0N/A try {
0N/A out.write(epoint.getHostName().getBytes("ISO-8859-1"));
0N/A } catch (java.io.UnsupportedEncodingException uee) {
0N/A assert false;
0N/A }
0N/A out.write((epoint.getPort() >> 8) & 0xff);
0N/A out.write((epoint.getPort() >> 0) & 0xff);
0N/A } else if (epoint.getAddress() instanceof Inet6Address) {
0N/A out.write(IPV6);
0N/A out.write(epoint.getAddress().getAddress());
0N/A out.write((epoint.getPort() >> 8) & 0xff);
0N/A out.write((epoint.getPort() >> 0) & 0xff);
0N/A } else {
0N/A out.write(IPV4);
0N/A out.write(epoint.getAddress().getAddress());
0N/A out.write((epoint.getPort() >> 8) & 0xff);
0N/A out.write((epoint.getPort() >> 0) & 0xff);
0N/A }
0N/A out.flush();
0N/A data = new byte[4];
2226N/A i = readSocksReply(in, data, deadlineMillis);
0N/A if (i != 4)
0N/A throw new SocketException("Reply from SOCKS server has bad length");
0N/A SocketException ex = null;
1305N/A int len;
0N/A byte[] addr;
0N/A switch (data[1]) {
0N/A case REQUEST_OK:
0N/A // success!
0N/A switch(data[3]) {
0N/A case IPV4:
0N/A addr = new byte[4];
2226N/A i = readSocksReply(in, addr, deadlineMillis);
0N/A if (i != 4)
0N/A throw new SocketException("Reply from SOCKS server badly formatted");
0N/A data = new byte[2];
2226N/A i = readSocksReply(in, data, deadlineMillis);
0N/A if (i != 2)
0N/A throw new SocketException("Reply from SOCKS server badly formatted");
0N/A break;
0N/A case DOMAIN_NAME:
0N/A len = data[1];
0N/A byte[] host = new byte[len];
2226N/A i = readSocksReply(in, host, deadlineMillis);
0N/A if (i != len)
0N/A throw new SocketException("Reply from SOCKS server badly formatted");
0N/A data = new byte[2];
2226N/A i = readSocksReply(in, data, deadlineMillis);
0N/A if (i != 2)
0N/A throw new SocketException("Reply from SOCKS server badly formatted");
0N/A break;
0N/A case IPV6:
0N/A len = data[1];
0N/A addr = new byte[len];
2226N/A i = readSocksReply(in, addr, deadlineMillis);
0N/A if (i != len)
0N/A throw new SocketException("Reply from SOCKS server badly formatted");
0N/A data = new byte[2];
2226N/A i = readSocksReply(in, data, deadlineMillis);
0N/A if (i != 2)
0N/A throw new SocketException("Reply from SOCKS server badly formatted");
0N/A break;
0N/A default:
0N/A ex = new SocketException("Reply from SOCKS server contains wrong code");
0N/A break;
0N/A }
0N/A break;
0N/A case GENERAL_FAILURE:
0N/A ex = new SocketException("SOCKS server general failure");
0N/A break;
0N/A case NOT_ALLOWED:
0N/A ex = new SocketException("SOCKS: Connection not allowed by ruleset");
0N/A break;
0N/A case NET_UNREACHABLE:
0N/A ex = new SocketException("SOCKS: Network unreachable");
0N/A break;
0N/A case HOST_UNREACHABLE:
0N/A ex = new SocketException("SOCKS: Host unreachable");
0N/A break;
0N/A case CONN_REFUSED:
0N/A ex = new SocketException("SOCKS: Connection refused");
0N/A break;
0N/A case TTL_EXPIRED:
0N/A ex = new SocketException("SOCKS: TTL expired");
0N/A break;
0N/A case CMD_NOT_SUPPORTED:
0N/A ex = new SocketException("SOCKS: Command not supported");
0N/A break;
0N/A case ADDR_TYPE_NOT_SUP:
0N/A ex = new SocketException("SOCKS: address type not supported");
0N/A break;
0N/A }
0N/A if (ex != null) {
0N/A in.close();
0N/A out.close();
0N/A throw ex;
0N/A }
0N/A external_address = epoint;
0N/A }
0N/A
0N/A private void bindV4(InputStream in, OutputStream out,
0N/A InetAddress baddr,
0N/A int lport) throws IOException {
0N/A if (!(baddr instanceof Inet4Address)) {
0N/A throw new SocketException("SOCKS V4 requires IPv4 only addresses");
0N/A }
0N/A super.bind(baddr, lport);
0N/A byte[] addr1 = baddr.getAddress();
0N/A /* Test for AnyLocal */
0N/A InetAddress naddr = baddr;
0N/A if (naddr.isAnyLocalAddress()) {
6319N/A naddr = AccessController.doPrivileged(
6319N/A new PrivilegedAction<InetAddress>() {
6319N/A public InetAddress run() {
6319N/A return cmdsock.getLocalAddress();
6319N/A
6319N/A }
6319N/A });
0N/A addr1 = naddr.getAddress();
0N/A }
0N/A out.write(PROTO_VERS4);
0N/A out.write(BIND);
0N/A out.write((super.getLocalPort() >> 8) & 0xff);
0N/A out.write((super.getLocalPort() >> 0) & 0xff);
0N/A out.write(addr1);
1503N/A String userName = getUserName();
0N/A try {
0N/A out.write(userName.getBytes("ISO-8859-1"));
0N/A } catch (java.io.UnsupportedEncodingException uee) {
0N/A assert false;
0N/A }
0N/A out.write(0);
0N/A out.flush();
0N/A byte[] data = new byte[8];
0N/A int n = readSocksReply(in, data);
0N/A if (n != 8)
0N/A throw new SocketException("Reply from SOCKS server has bad length: " + n);
0N/A if (data[0] != 0 && data[0] != 4)
0N/A throw new SocketException("Reply from SOCKS server has bad version");
0N/A SocketException ex = null;
0N/A switch (data[1]) {
0N/A case 90:
0N/A // Success!
0N/A external_address = new InetSocketAddress(baddr, lport);
0N/A break;
0N/A case 91:
0N/A ex = new SocketException("SOCKS request rejected");
0N/A break;
0N/A case 92:
0N/A ex = new SocketException("SOCKS server couldn't reach destination");
0N/A break;
0N/A case 93:
0N/A ex = new SocketException("SOCKS authentication failed");
0N/A break;
0N/A default:
0N/A ex = new SocketException("Reply from SOCKS server contains bad status");
0N/A break;
0N/A }
0N/A if (ex != null) {
0N/A in.close();
0N/A out.close();
0N/A throw ex;
0N/A }
0N/A
0N/A }
0N/A
0N/A /**
0N/A * Sends the Bind request to the SOCKS proxy. In the SOCKS protocol, bind
0N/A * means "accept incoming connection from", so the SocketAddress is the
0N/A * the one of the host we do accept connection from.
0N/A *
0N/A * @param addr the Socket address of the remote host.
0N/A * @exception IOException if an I/O error occurs when binding this socket.
0N/A */
0N/A protected synchronized void socksBind(InetSocketAddress saddr) throws IOException {
0N/A if (socket != null) {
0N/A // this is a client socket, not a server socket, don't
0N/A // call the SOCKS proxy for a bind!
0N/A return;
0N/A }
0N/A
0N/A // Connects to the SOCKS server
0N/A
0N/A if (server == null) {
0N/A // This is the general case
0N/A // server is not null only when the socket was created with a
0N/A // specified proxy in which case it does bypass the ProxySelector
28N/A ProxySelector sel = java.security.AccessController.doPrivileged(
28N/A new java.security.PrivilegedAction<ProxySelector>() {
28N/A public ProxySelector run() {
0N/A return ProxySelector.getDefault();
0N/A }
0N/A });
0N/A if (sel == null) {
0N/A /*
0N/A * No default proxySelector --> direct connection
0N/A */
0N/A return;
0N/A }
1305N/A URI uri;
0N/A // Use getHostString() to avoid reverse lookups
0N/A String host = saddr.getHostString();
0N/A // IPv6 litteral?
0N/A if (saddr.getAddress() instanceof Inet6Address &&
0N/A (!host.startsWith("[")) && (host.indexOf(":") >= 0)) {
0N/A host = "[" + host + "]";
0N/A }
0N/A try {
0N/A uri = new URI("serversocket://" + ParseUtil.encodePath(host) + ":"+ saddr.getPort());
0N/A } catch (URISyntaxException e) {
0N/A // This shouldn't happen
0N/A assert false : e;
1305N/A uri = null;
0N/A }
0N/A Proxy p = null;
0N/A Exception savedExc = null;
0N/A java.util.Iterator<Proxy> iProxy = null;
0N/A iProxy = sel.select(uri).iterator();
0N/A if (iProxy == null || !(iProxy.hasNext())) {
0N/A return;
0N/A }
0N/A while (iProxy.hasNext()) {
0N/A p = iProxy.next();
0N/A if (p == null || p == Proxy.NO_PROXY) {
0N/A return;
0N/A }
0N/A if (p.type() != Proxy.Type.SOCKS)
0N/A throw new SocketException("Unknown proxy type : " + p.type());
0N/A if (!(p.address() instanceof InetSocketAddress))
0N/A throw new SocketException("Unknow address type for proxy: " + p);
0N/A // Use getHostString() to avoid reverse lookups
0N/A server = ((InetSocketAddress) p.address()).getHostString();
1305N/A serverPort = ((InetSocketAddress) p.address()).getPort();
3393N/A if (p instanceof SocksProxy) {
3393N/A if (((SocksProxy)p).protocolVersion() == 4) {
3393N/A useV4 = true;
3393N/A }
3393N/A }
0N/A
0N/A // Connects to the SOCKS server
0N/A try {
28N/A AccessController.doPrivileged(
28N/A new PrivilegedExceptionAction<Void>() {
28N/A public Void run() throws Exception {
0N/A cmdsock = new Socket(new PlainSocketImpl());
1305N/A cmdsock.connect(new InetSocketAddress(server, serverPort));
0N/A cmdIn = cmdsock.getInputStream();
0N/A cmdOut = cmdsock.getOutputStream();
0N/A return null;
0N/A }
0N/A });
0N/A } catch (Exception e) {
0N/A // Ooops, let's notify the ProxySelector
0N/A sel.connectFailed(uri,p.address(),new SocketException(e.getMessage()));
0N/A server = null;
1305N/A serverPort = -1;
0N/A cmdsock = null;
0N/A savedExc = e;
0N/A // Will continue the while loop and try the next proxy
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * If server is still null at this point, none of the proxy
0N/A * worked
0N/A */
0N/A if (server == null || cmdsock == null) {
0N/A throw new SocketException("Can't connect to SOCKS proxy:"
0N/A + savedExc.getMessage());
0N/A }
0N/A } else {
0N/A try {
28N/A AccessController.doPrivileged(
28N/A new PrivilegedExceptionAction<Void>() {
28N/A public Void run() throws Exception {
0N/A cmdsock = new Socket(new PlainSocketImpl());
1305N/A cmdsock.connect(new InetSocketAddress(server, serverPort));
0N/A cmdIn = cmdsock.getInputStream();
0N/A cmdOut = cmdsock.getOutputStream();
0N/A return null;
0N/A }
0N/A });
0N/A } catch (Exception e) {
0N/A throw new SocketException(e.getMessage());
0N/A }
0N/A }
0N/A BufferedOutputStream out = new BufferedOutputStream(cmdOut, 512);
0N/A InputStream in = cmdIn;
0N/A if (useV4) {
0N/A bindV4(in, out, saddr.getAddress(), saddr.getPort());
0N/A return;
0N/A }
0N/A out.write(PROTO_VERS);
0N/A out.write(2);
0N/A out.write(NO_AUTH);
0N/A out.write(USER_PASSW);
0N/A out.flush();
0N/A byte[] data = new byte[2];
0N/A int i = readSocksReply(in, data);
0N/A if (i != 2 || ((int)data[0]) != PROTO_VERS) {
0N/A // Maybe it's not a V5 sever after all
0N/A // Let's try V4 before we give up
0N/A bindV4(in, out, saddr.getAddress(), saddr.getPort());
0N/A return;
0N/A }
0N/A if (((int)data[1]) == NO_METHODS)
0N/A throw new SocketException("SOCKS : No acceptable methods");
0N/A if (!authenticate(data[1], in, out)) {
0N/A throw new SocketException("SOCKS : authentication failed");
0N/A }
0N/A // We're OK. Let's issue the BIND command.
0N/A out.write(PROTO_VERS);
0N/A out.write(BIND);
0N/A out.write(0);
0N/A int lport = saddr.getPort();
0N/A if (saddr.isUnresolved()) {
0N/A out.write(DOMAIN_NAME);
0N/A out.write(saddr.getHostName().length());
0N/A try {
0N/A out.write(saddr.getHostName().getBytes("ISO-8859-1"));
0N/A } catch (java.io.UnsupportedEncodingException uee) {
0N/A assert false;
0N/A }
0N/A out.write((lport >> 8) & 0xff);
0N/A out.write((lport >> 0) & 0xff);
0N/A } else if (saddr.getAddress() instanceof Inet4Address) {
0N/A byte[] addr1 = saddr.getAddress().getAddress();
0N/A out.write(IPV4);
0N/A out.write(addr1);
0N/A out.write((lport >> 8) & 0xff);
0N/A out.write((lport >> 0) & 0xff);
0N/A out.flush();
0N/A } else if (saddr.getAddress() instanceof Inet6Address) {
0N/A byte[] addr1 = saddr.getAddress().getAddress();
0N/A out.write(IPV6);
0N/A out.write(addr1);
0N/A out.write((lport >> 8) & 0xff);
0N/A out.write((lport >> 0) & 0xff);
0N/A out.flush();
0N/A } else {
0N/A cmdsock.close();
0N/A throw new SocketException("unsupported address type : " + saddr);
0N/A }
0N/A data = new byte[4];
0N/A i = readSocksReply(in, data);
0N/A SocketException ex = null;
0N/A int len, nport;
0N/A byte[] addr;
0N/A switch (data[1]) {
0N/A case REQUEST_OK:
0N/A // success!
0N/A switch(data[3]) {
0N/A case IPV4:
0N/A addr = new byte[4];
0N/A i = readSocksReply(in, addr);
0N/A if (i != 4)
0N/A throw new SocketException("Reply from SOCKS server badly formatted");
0N/A data = new byte[2];
0N/A i = readSocksReply(in, data);
0N/A if (i != 2)
0N/A throw new SocketException("Reply from SOCKS server badly formatted");
0N/A nport = ((int)data[0] & 0xff) << 8;
0N/A nport += ((int)data[1] & 0xff);
0N/A external_address =
0N/A new InetSocketAddress(new Inet4Address("", addr) , nport);
0N/A break;
0N/A case DOMAIN_NAME:
0N/A len = data[1];
0N/A byte[] host = new byte[len];
0N/A i = readSocksReply(in, host);
0N/A if (i != len)
0N/A throw new SocketException("Reply from SOCKS server badly formatted");
0N/A data = new byte[2];
0N/A i = readSocksReply(in, data);
0N/A if (i != 2)
0N/A throw new SocketException("Reply from SOCKS server badly formatted");
0N/A nport = ((int)data[0] & 0xff) << 8;
0N/A nport += ((int)data[1] & 0xff);
0N/A external_address = new InetSocketAddress(new String(host), nport);
0N/A break;
0N/A case IPV6:
0N/A len = data[1];
0N/A addr = new byte[len];
0N/A i = readSocksReply(in, addr);
0N/A if (i != len)
0N/A throw new SocketException("Reply from SOCKS server badly formatted");
0N/A data = new byte[2];
0N/A i = readSocksReply(in, data);
0N/A if (i != 2)
0N/A throw new SocketException("Reply from SOCKS server badly formatted");
0N/A nport = ((int)data[0] & 0xff) << 8;
0N/A nport += ((int)data[1] & 0xff);
0N/A external_address =
0N/A new InetSocketAddress(new Inet6Address("", addr), nport);
0N/A break;
0N/A }
0N/A break;
0N/A case GENERAL_FAILURE:
0N/A ex = new SocketException("SOCKS server general failure");
0N/A break;
0N/A case NOT_ALLOWED:
0N/A ex = new SocketException("SOCKS: Bind not allowed by ruleset");
0N/A break;
0N/A case NET_UNREACHABLE:
0N/A ex = new SocketException("SOCKS: Network unreachable");
0N/A break;
0N/A case HOST_UNREACHABLE:
0N/A ex = new SocketException("SOCKS: Host unreachable");
0N/A break;
0N/A case CONN_REFUSED:
0N/A ex = new SocketException("SOCKS: Connection refused");
0N/A break;
0N/A case TTL_EXPIRED:
0N/A ex = new SocketException("SOCKS: TTL expired");
0N/A break;
0N/A case CMD_NOT_SUPPORTED:
0N/A ex = new SocketException("SOCKS: Command not supported");
0N/A break;
0N/A case ADDR_TYPE_NOT_SUP:
0N/A ex = new SocketException("SOCKS: address type not supported");
0N/A break;
0N/A }
0N/A if (ex != null) {
0N/A in.close();
0N/A out.close();
0N/A cmdsock.close();
0N/A cmdsock = null;
0N/A throw ex;
0N/A }
0N/A cmdIn = in;
0N/A cmdOut = out;
0N/A }
0N/A
0N/A /**
0N/A * Accepts a connection from a specific host.
0N/A *
0N/A * @param s the accepted connection.
0N/A * @param saddr the socket address of the host we do accept
0N/A * connection from
0N/A * @exception IOException if an I/O error occurs when accepting the
0N/A * connection.
0N/A */
0N/A protected void acceptFrom(SocketImpl s, InetSocketAddress saddr) throws IOException {
0N/A if (cmdsock == null) {
0N/A // Not a Socks ServerSocket.
0N/A return;
0N/A }
0N/A InputStream in = cmdIn;
0N/A // Sends the "SOCKS BIND" request.
0N/A socksBind(saddr);
0N/A in.read();
0N/A int i = in.read();
0N/A in.read();
0N/A SocketException ex = null;
0N/A int nport;
0N/A byte[] addr;
0N/A InetSocketAddress real_end = null;
0N/A switch (i) {
0N/A case REQUEST_OK:
0N/A // success!
0N/A i = in.read();
0N/A switch(i) {
0N/A case IPV4:
0N/A addr = new byte[4];
0N/A readSocksReply(in, addr);
0N/A nport = in.read() << 8;
0N/A nport += in.read();
0N/A real_end =
0N/A new InetSocketAddress(new Inet4Address("", addr) , nport);
0N/A break;
0N/A case DOMAIN_NAME:
0N/A int len = in.read();
0N/A addr = new byte[len];
0N/A readSocksReply(in, addr);
0N/A nport = in.read() << 8;
0N/A nport += in.read();
0N/A real_end = new InetSocketAddress(new String(addr), nport);
0N/A break;
0N/A case IPV6:
0N/A addr = new byte[16];
0N/A readSocksReply(in, addr);
0N/A nport = in.read() << 8;
0N/A nport += in.read();
0N/A real_end =
0N/A new InetSocketAddress(new Inet6Address("", addr), nport);
0N/A break;
0N/A }
0N/A break;
0N/A case GENERAL_FAILURE:
0N/A ex = new SocketException("SOCKS server general failure");
0N/A break;
0N/A case NOT_ALLOWED:
0N/A ex = new SocketException("SOCKS: Accept not allowed by ruleset");
0N/A break;
0N/A case NET_UNREACHABLE:
0N/A ex = new SocketException("SOCKS: Network unreachable");
0N/A break;
0N/A case HOST_UNREACHABLE:
0N/A ex = new SocketException("SOCKS: Host unreachable");
0N/A break;
0N/A case CONN_REFUSED:
0N/A ex = new SocketException("SOCKS: Connection refused");
0N/A break;
0N/A case TTL_EXPIRED:
0N/A ex = new SocketException("SOCKS: TTL expired");
0N/A break;
0N/A case CMD_NOT_SUPPORTED:
0N/A ex = new SocketException("SOCKS: Command not supported");
0N/A break;
0N/A case ADDR_TYPE_NOT_SUP:
0N/A ex = new SocketException("SOCKS: address type not supported");
0N/A break;
0N/A }
0N/A if (ex != null) {
0N/A cmdIn.close();
0N/A cmdOut.close();
0N/A cmdsock.close();
0N/A cmdsock = null;
0N/A throw ex;
0N/A }
0N/A
0N/A /**
0N/A * This is where we have to do some fancy stuff.
0N/A * The datastream from the socket "accepted" by the proxy will
0N/A * come through the cmdSocket. So we have to swap the socketImpls
0N/A */
0N/A if (s instanceof SocksSocketImpl) {
0N/A ((SocksSocketImpl)s).external_address = real_end;
0N/A }
0N/A if (s instanceof PlainSocketImpl) {
0N/A PlainSocketImpl psi = (PlainSocketImpl) s;
0N/A psi.setInputStream((SocketInputStream) in);
0N/A psi.setFileDescriptor(cmdsock.getImpl().getFileDescriptor());
0N/A psi.setAddress(cmdsock.getImpl().getInetAddress());
0N/A psi.setPort(cmdsock.getImpl().getPort());
0N/A psi.setLocalPort(cmdsock.getImpl().getLocalPort());
0N/A } else {
0N/A s.fd = cmdsock.getImpl().fd;
0N/A s.address = cmdsock.getImpl().address;
0N/A s.port = cmdsock.getImpl().port;
0N/A s.localport = cmdsock.getImpl().localport;
0N/A }
0N/A
0N/A // Need to do that so that the socket won't be closed
0N/A // when the ServerSocket is closed by the user.
0N/A // It kinds of detaches the Socket because it is now
0N/A // used elsewhere.
0N/A cmdsock = null;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Returns the value of this socket's <code>address</code> field.
0N/A *
0N/A * @return the value of this socket's <code>address</code> field.
0N/A * @see java.net.SocketImpl#address
0N/A */
1305N/A @Override
0N/A protected InetAddress getInetAddress() {
0N/A if (external_address != null)
0N/A return external_address.getAddress();
0N/A else
0N/A return super.getInetAddress();
0N/A }
0N/A
0N/A /**
0N/A * Returns the value of this socket's <code>port</code> field.
0N/A *
0N/A * @return the value of this socket's <code>port</code> field.
0N/A * @see java.net.SocketImpl#port
0N/A */
1305N/A @Override
0N/A protected int getPort() {
0N/A if (external_address != null)
0N/A return external_address.getPort();
0N/A else
0N/A return super.getPort();
0N/A }
0N/A
1305N/A @Override
0N/A protected int getLocalPort() {
0N/A if (socket != null)
0N/A return super.getLocalPort();
0N/A if (external_address != null)
0N/A return external_address.getPort();
0N/A else
0N/A return super.getLocalPort();
0N/A }
0N/A
1305N/A @Override
0N/A protected void close() throws IOException {
0N/A if (cmdsock != null)
0N/A cmdsock.close();
0N/A cmdsock = null;
0N/A super.close();
0N/A }
0N/A
1503N/A private String getUserName() {
1503N/A String userName = "";
1503N/A if (applicationSetProxy) {
1503N/A try {
1503N/A userName = System.getProperty("user.name");
1503N/A } catch (SecurityException se) { /* swallow Exception */ }
1503N/A } else {
1503N/A userName = java.security.AccessController.doPrivileged(
1503N/A new sun.security.action.GetPropertyAction("user.name"));
1503N/A }
1503N/A return userName;
1503N/A }
0N/A}