--- a/src/java.base/share/classes/java/net/HttpConnectSocketImpl.java Tue Jan 22 15:33:34 2019 +0800
+++ b/src/java.base/share/classes/java/net/HttpConnectSocketImpl.java Thu Jan 24 15:48:05 2019 +0000
@@ -197,14 +197,4 @@
else
return super.getPort();
}
-
- @Override
- protected int getLocalPort() {
- if (socket != null)
- return super.getLocalPort();
- if (external_address != null)
- return external_address.getPort();
- else
- return super.getLocalPort();
- }
}
--- a/src/java.base/share/classes/java/net/SocksSocketImpl.java Tue Jan 22 15:33:34 2019 +0800
+++ b/src/java.base/share/classes/java/net/SocksSocketImpl.java Thu Jan 24 15:48:05 2019 +0000
@@ -28,14 +28,11 @@
import java.io.OutputStream;
import java.io.BufferedOutputStream;
import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.security.PrivilegedExceptionAction;
import jdk.internal.util.StaticProperty;
import sun.net.SocksProxy;
import sun.net.spi.DefaultProxySelector;
import sun.net.www.ParseUtil;
-/* import org.ietf.jgss.*; */
/**
* SOCKS (V4 & V5) TCP socket implementation (RFC 1928).
@@ -51,19 +48,11 @@
private Socket cmdsock = null;
private InputStream cmdIn = null;
private OutputStream cmdOut = null;
- /* true if the Proxy has been set programmatically */
- private boolean applicationSetProxy; /* false */
-
SocksSocketImpl() {
// Nothing needed
}
- SocksSocketImpl(String server, int port) {
- this.server = server;
- this.serverPort = (port == -1 ? DEFAULT_PORT : port);
- }
-
SocksSocketImpl(Proxy proxy) {
SocketAddress a = proxy.address();
if (a instanceof InetSocketAddress) {
@@ -75,10 +64,6 @@
useV4 = useV4(proxy);
}
- void setV4() {
- useV4 = true;
- }
-
private static boolean useV4(Proxy proxy) {
if (proxy instanceof SocksProxy
&& ((SocksProxy)proxy).protocolVersion() == 4) {
@@ -123,10 +108,6 @@
throw new SocketTimeoutException();
}
- private int readSocksReply(InputStream in, byte[] data) throws IOException {
- return readSocksReply(in, data, 0L);
- }
-
private int readSocksReply(InputStream in, byte[] data, long deadlineMillis) throws IOException {
int len = data.length;
int received = 0;
@@ -144,14 +125,6 @@
return received;
}
- /**
- * Provides the authentication mechanism required by the proxy.
- */
- private boolean authenticate(byte method, InputStream in,
- BufferedOutputStream out) throws IOException {
- return authenticate(method, in, out, 0L);
- }
-
private boolean authenticate(byte method, InputStream in,
BufferedOutputStream out,
long deadlineMillis) throws IOException {
@@ -212,60 +185,6 @@
/* Authentication succeeded */
return true;
}
- /**
- * GSSAPI authentication mechanism.
- * Unfortunately the RFC seems out of sync with the Reference
- * implementation. I'll leave this in for future completion.
- */
-// if (method == GSSAPI) {
-// try {
-// GSSManager manager = GSSManager.getInstance();
-// GSSName name = manager.createName("SERVICE:socks@"+server,
-// null);
-// GSSContext context = manager.createContext(name, null, null,
-// GSSContext.DEFAULT_LIFETIME);
-// context.requestMutualAuth(true);
-// context.requestReplayDet(true);
-// context.requestSequenceDet(true);
-// context.requestCredDeleg(true);
-// byte []inToken = new byte[0];
-// while (!context.isEstablished()) {
-// byte[] outToken
-// = context.initSecContext(inToken, 0, inToken.length);
-// // send the output token if generated
-// if (outToken != null) {
-// out.write(1);
-// out.write(1);
-// out.writeShort(outToken.length);
-// out.write(outToken);
-// out.flush();
-// data = new byte[2];
-// i = readSocksReply(in, data, deadlineMillis);
-// if (i != 2 || data[1] == 0xff) {
-// in.close();
-// out.close();
-// return false;
-// }
-// i = readSocksReply(in, data, deadlineMillis);
-// int len = 0;
-// len = ((int)data[0] & 0xff) << 8;
-// len += data[1];
-// data = new byte[len];
-// i = readSocksReply(in, data, deadlineMillis);
-// if (i == len)
-// return true;
-// in.close();
-// out.close();
-// }
-// }
-// } catch (GSSException e) {
-// /* RFC 1961 states that if Context initialisation fails the connection
-// MUST be closed */
-// e.printStackTrace();
-// in.close();
-// out.close();
-// }
-// }
return false;
}
@@ -590,450 +509,6 @@
external_address = epoint;
}
- private void bindV4(InputStream in, OutputStream out,
- InetAddress baddr,
- int lport) throws IOException {
- if (!(baddr instanceof Inet4Address)) {
- throw new SocketException("SOCKS V4 requires IPv4 only addresses");
- }
- super.bind(baddr, lport);
- byte[] addr1 = baddr.getAddress();
- /* Test for AnyLocal */
- InetAddress naddr = baddr;
- if (naddr.isAnyLocalAddress()) {
- naddr = AccessController.doPrivileged(
- new PrivilegedAction<>() {
- public InetAddress run() {
- return cmdsock.getLocalAddress();
-
- }
- });
- addr1 = naddr.getAddress();
- }
- out.write(PROTO_VERS4);
- out.write(BIND);
- out.write((super.getLocalPort() >> 8) & 0xff);
- out.write((super.getLocalPort() >> 0) & 0xff);
- out.write(addr1);
- String userName = getUserName();
- try {
- out.write(userName.getBytes("ISO-8859-1"));
- } catch (java.io.UnsupportedEncodingException uee) {
- assert false;
- }
- out.write(0);
- out.flush();
- byte[] data = new byte[8];
- int n = readSocksReply(in, data);
- if (n != 8)
- throw new SocketException("Reply from SOCKS server has bad length: " + n);
- if (data[0] != 0 && data[0] != 4)
- throw new SocketException("Reply from SOCKS server has bad version");
- SocketException ex = null;
- switch (data[1]) {
- case 90:
- // Success!
- external_address = new InetSocketAddress(baddr, lport);
- break;
- case 91:
- ex = new SocketException("SOCKS request rejected");
- break;
- case 92:
- ex = new SocketException("SOCKS server couldn't reach destination");
- break;
- case 93:
- ex = new SocketException("SOCKS authentication failed");
- break;
- default:
- ex = new SocketException("Reply from SOCKS server contains bad status");
- break;
- }
- if (ex != null) {
- in.close();
- out.close();
- throw ex;
- }
-
- }
-
- /**
- * Sends the Bind request to the SOCKS proxy. In the SOCKS protocol, bind
- * means "accept incoming connection from", so the SocketAddress is
- * the one of the host we do accept connection from.
- *
- * @param saddr the Socket address of the remote host.
- * @exception IOException if an I/O error occurs when binding this socket.
- */
- protected synchronized void socksBind(InetSocketAddress saddr) throws IOException {
- if (socket != null) {
- // this is a client socket, not a server socket, don't
- // call the SOCKS proxy for a bind!
- return;
- }
-
- // Connects to the SOCKS server
-
- if (server == null) {
- // This is the general case
- // server is not null only when the socket was created with a
- // specified proxy in which case it does bypass the ProxySelector
- ProxySelector sel = java.security.AccessController.doPrivileged(
- new java.security.PrivilegedAction<>() {
- public ProxySelector run() {
- return ProxySelector.getDefault();
- }
- });
- if (sel == null) {
- /*
- * No default proxySelector --> direct connection
- */
- return;
- }
- URI uri;
- // Use getHostString() to avoid reverse lookups
- String host = saddr.getHostString();
- // IPv6 literal?
- if (saddr.getAddress() instanceof Inet6Address &&
- (!host.startsWith("[")) && (host.indexOf(':') >= 0)) {
- host = "[" + host + "]";
- }
- try {
- uri = new URI("serversocket://" + ParseUtil.encodePath(host) + ":"+ saddr.getPort());
- } catch (URISyntaxException e) {
- // This shouldn't happen
- assert false : e;
- uri = null;
- }
- Proxy p = null;
- Exception savedExc = null;
- java.util.Iterator<Proxy> iProxy = null;
- iProxy = sel.select(uri).iterator();
- if (iProxy == null || !(iProxy.hasNext())) {
- return;
- }
- while (iProxy.hasNext()) {
- p = iProxy.next();
- if (p == null || p.type() != Proxy.Type.SOCKS) {
- return;
- }
-
- if (!(p.address() instanceof InetSocketAddress))
- throw new SocketException("Unknown address type for proxy: " + p);
- // Use getHostString() to avoid reverse lookups
- server = ((InetSocketAddress) p.address()).getHostString();
- serverPort = ((InetSocketAddress) p.address()).getPort();
- useV4 = useV4(p);
-
- // Connects to the SOCKS server
- try {
- AccessController.doPrivileged(
- new PrivilegedExceptionAction<>() {
- public Void run() throws Exception {
- cmdsock = new Socket(new PlainSocketImpl());
- cmdsock.connect(new InetSocketAddress(server, serverPort));
- cmdIn = cmdsock.getInputStream();
- cmdOut = cmdsock.getOutputStream();
- return null;
- }
- });
- } catch (Exception e) {
- // Ooops, let's notify the ProxySelector
- sel.connectFailed(uri,p.address(),new SocketException(e.getMessage()));
- server = null;
- serverPort = -1;
- cmdsock = null;
- savedExc = e;
- // Will continue the while loop and try the next proxy
- }
- }
-
- /*
- * If server is still null at this point, none of the proxy
- * worked
- */
- if (server == null || cmdsock == null) {
- throw new SocketException("Can't connect to SOCKS proxy:"
- + savedExc.getMessage());
- }
- } else {
- try {
- AccessController.doPrivileged(
- new PrivilegedExceptionAction<>() {
- public Void run() throws Exception {
- cmdsock = new Socket(new PlainSocketImpl());
- cmdsock.connect(new InetSocketAddress(server, serverPort));
- cmdIn = cmdsock.getInputStream();
- cmdOut = cmdsock.getOutputStream();
- return null;
- }
- });
- } catch (Exception e) {
- throw new SocketException(e.getMessage());
- }
- }
- BufferedOutputStream out = new BufferedOutputStream(cmdOut, 512);
- InputStream in = cmdIn;
- if (useV4) {
- bindV4(in, out, saddr.getAddress(), saddr.getPort());
- return;
- }
- out.write(PROTO_VERS);
- out.write(2);
- out.write(NO_AUTH);
- out.write(USER_PASSW);
- out.flush();
- byte[] data = new byte[2];
- int i = readSocksReply(in, data);
- if (i != 2 || ((int)data[0]) != PROTO_VERS) {
- // Maybe it's not a V5 sever after all
- // Let's try V4 before we give up
- bindV4(in, out, saddr.getAddress(), saddr.getPort());
- return;
- }
- if (((int)data[1]) == NO_METHODS)
- throw new SocketException("SOCKS : No acceptable methods");
- if (!authenticate(data[1], in, out)) {
- throw new SocketException("SOCKS : authentication failed");
- }
- // We're OK. Let's issue the BIND command.
- out.write(PROTO_VERS);
- out.write(BIND);
- out.write(0);
- int lport = saddr.getPort();
- if (saddr.isUnresolved()) {
- out.write(DOMAIN_NAME);
- out.write(saddr.getHostName().length());
- try {
- out.write(saddr.getHostName().getBytes("ISO-8859-1"));
- } catch (java.io.UnsupportedEncodingException uee) {
- assert false;
- }
- out.write((lport >> 8) & 0xff);
- out.write((lport >> 0) & 0xff);
- } else if (saddr.getAddress() instanceof Inet4Address) {
- byte[] addr1 = saddr.getAddress().getAddress();
- out.write(IPV4);
- out.write(addr1);
- out.write((lport >> 8) & 0xff);
- out.write((lport >> 0) & 0xff);
- out.flush();
- } else if (saddr.getAddress() instanceof Inet6Address) {
- byte[] addr1 = saddr.getAddress().getAddress();
- out.write(IPV6);
- out.write(addr1);
- out.write((lport >> 8) & 0xff);
- out.write((lport >> 0) & 0xff);
- out.flush();
- } else {
- cmdsock.close();
- throw new SocketException("unsupported address type : " + saddr);
- }
- data = new byte[4];
- i = readSocksReply(in, data);
- SocketException ex = null;
- int len, nport;
- byte[] addr;
- switch (data[1]) {
- case REQUEST_OK:
- // success!
- switch(data[3]) {
- case IPV4:
- addr = new byte[4];
- i = readSocksReply(in, addr);
- if (i != 4)
- throw new SocketException("Reply from SOCKS server badly formatted");
- data = new byte[2];
- i = readSocksReply(in, data);
- if (i != 2)
- throw new SocketException("Reply from SOCKS server badly formatted");
- nport = ((int)data[0] & 0xff) << 8;
- nport += ((int)data[1] & 0xff);
- external_address =
- new InetSocketAddress(new Inet4Address("", addr) , nport);
- break;
- case DOMAIN_NAME:
- len = data[1];
- byte[] host = new byte[len];
- i = readSocksReply(in, host);
- if (i != len)
- throw new SocketException("Reply from SOCKS server badly formatted");
- data = new byte[2];
- i = readSocksReply(in, data);
- if (i != 2)
- throw new SocketException("Reply from SOCKS server badly formatted");
- nport = ((int)data[0] & 0xff) << 8;
- nport += ((int)data[1] & 0xff);
- external_address = new InetSocketAddress(new String(host), nport);
- break;
- case IPV6:
- len = data[1];
- addr = new byte[len];
- i = readSocksReply(in, addr);
- if (i != len)
- throw new SocketException("Reply from SOCKS server badly formatted");
- data = new byte[2];
- i = readSocksReply(in, data);
- if (i != 2)
- throw new SocketException("Reply from SOCKS server badly formatted");
- nport = ((int)data[0] & 0xff) << 8;
- nport += ((int)data[1] & 0xff);
- external_address =
- new InetSocketAddress(new Inet6Address("", addr), nport);
- break;
- }
- break;
- case GENERAL_FAILURE:
- ex = new SocketException("SOCKS server general failure");
- break;
- case NOT_ALLOWED:
- ex = new SocketException("SOCKS: Bind not allowed by ruleset");
- break;
- case NET_UNREACHABLE:
- ex = new SocketException("SOCKS: Network unreachable");
- break;
- case HOST_UNREACHABLE:
- ex = new SocketException("SOCKS: Host unreachable");
- break;
- case CONN_REFUSED:
- ex = new SocketException("SOCKS: Connection refused");
- break;
- case TTL_EXPIRED:
- ex = new SocketException("SOCKS: TTL expired");
- break;
- case CMD_NOT_SUPPORTED:
- ex = new SocketException("SOCKS: Command not supported");
- break;
- case ADDR_TYPE_NOT_SUP:
- ex = new SocketException("SOCKS: address type not supported");
- break;
- }
- if (ex != null) {
- in.close();
- out.close();
- cmdsock.close();
- cmdsock = null;
- throw ex;
- }
- cmdIn = in;
- cmdOut = out;
- }
-
- /**
- * Accepts a connection from a specific host.
- *
- * @param s the accepted connection.
- * @param saddr the socket address of the host we do accept
- * connection from
- * @exception IOException if an I/O error occurs when accepting the
- * connection.
- */
- protected void acceptFrom(SocketImpl s, InetSocketAddress saddr) throws IOException {
- if (cmdsock == null) {
- // Not a Socks ServerSocket.
- return;
- }
- InputStream in = cmdIn;
- // Sends the "SOCKS BIND" request.
- socksBind(saddr);
- in.read();
- int i = in.read();
- in.read();
- SocketException ex = null;
- int nport;
- byte[] addr;
- InetSocketAddress real_end = null;
- switch (i) {
- case REQUEST_OK:
- // success!
- i = in.read();
- switch(i) {
- case IPV4:
- addr = new byte[4];
- readSocksReply(in, addr);
- nport = in.read() << 8;
- nport += in.read();
- real_end =
- new InetSocketAddress(new Inet4Address("", addr) , nport);
- break;
- case DOMAIN_NAME:
- int len = in.read();
- addr = new byte[len];
- readSocksReply(in, addr);
- nport = in.read() << 8;
- nport += in.read();
- real_end = new InetSocketAddress(new String(addr), nport);
- break;
- case IPV6:
- addr = new byte[16];
- readSocksReply(in, addr);
- nport = in.read() << 8;
- nport += in.read();
- real_end =
- new InetSocketAddress(new Inet6Address("", addr), nport);
- break;
- }
- break;
- case GENERAL_FAILURE:
- ex = new SocketException("SOCKS server general failure");
- break;
- case NOT_ALLOWED:
- ex = new SocketException("SOCKS: Accept not allowed by ruleset");
- break;
- case NET_UNREACHABLE:
- ex = new SocketException("SOCKS: Network unreachable");
- break;
- case HOST_UNREACHABLE:
- ex = new SocketException("SOCKS: Host unreachable");
- break;
- case CONN_REFUSED:
- ex = new SocketException("SOCKS: Connection refused");
- break;
- case TTL_EXPIRED:
- ex = new SocketException("SOCKS: TTL expired");
- break;
- case CMD_NOT_SUPPORTED:
- ex = new SocketException("SOCKS: Command not supported");
- break;
- case ADDR_TYPE_NOT_SUP:
- ex = new SocketException("SOCKS: address type not supported");
- break;
- }
- if (ex != null) {
- cmdIn.close();
- cmdOut.close();
- cmdsock.close();
- cmdsock = null;
- throw ex;
- }
-
- /**
- * This is where we have to do some fancy stuff.
- * The datastream from the socket "accepted" by the proxy will
- * come through the cmdSocket. So we have to swap the socketImpls
- */
- if (s instanceof SocksSocketImpl) {
- ((SocksSocketImpl)s).external_address = real_end;
- }
- if (s instanceof PlainSocketImpl) {
- PlainSocketImpl psi = (PlainSocketImpl) s;
- psi.setInputStream((SocketInputStream) in);
- psi.setFileDescriptor(cmdsock.getImpl().getFileDescriptor());
- psi.setAddress(cmdsock.getImpl().getInetAddress());
- psi.setPort(cmdsock.getImpl().getPort());
- psi.setLocalPort(cmdsock.getImpl().getLocalPort());
- } else {
- s.fd = cmdsock.getImpl().fd;
- s.address = cmdsock.getImpl().address;
- s.port = cmdsock.getImpl().port;
- s.localport = cmdsock.getImpl().localport;
- }
-
- // Need to do that so that the socket won't be closed
- // when the ServerSocket is closed by the user.
- // It kinds of detaches the Socket because it is now
- // used elsewhere.
- cmdsock = null;
- }
/**
@@ -1065,16 +540,6 @@
}
@Override
- protected int getLocalPort() {
- if (socket != null)
- return super.getLocalPort();
- if (external_address != null)
- return external_address.getPort();
- else
- return super.getLocalPort();
- }
-
- @Override
protected void close() throws IOException {
if (cmdsock != null)
cmdsock.close();
@@ -1083,14 +548,6 @@
}
private String getUserName() {
- String userName = "";
- if (applicationSetProxy) {
- try {
- userName = System.getProperty("user.name");
- } catch (SecurityException se) { /* swallow Exception */ }
- } else {
- userName = StaticProperty.userName();
- }
- return userName;
+ return StaticProperty.userName();
}
}
--- a/test/jdk/java/net/Socks/SocksServer.java Tue Jan 22 15:33:34 2019 +0800
+++ b/test/jdk/java/net/Socks/SocksServer.java Thu Jan 24 15:48:05 2019 +0000
@@ -24,7 +24,7 @@
import java.io.*;
import java.util.HashMap;
-public class SocksServer extends Thread {
+public class SocksServer extends Thread implements Closeable {
// Some useful SOCKS constant
static final int PROTO_VERS4 = 4;
@@ -503,7 +503,7 @@
return port;
}
- public void terminate() {
+ public void close() {
done = true;
try { server.close(); } catch (IOException unused) {}
}
--- a/test/jdk/java/net/Socks/SocksV4Test.java Tue Jan 22 15:33:34 2019 +0800
+++ b/test/jdk/java/net/Socks/SocksV4Test.java Thu Jan 24 15:48:05 2019 +0000
@@ -26,36 +26,80 @@
* @bug 4727547
* @summary SocksSocketImpl throws NullPointerException
* @build SocksServer
- * @run main SocksV4Test
+ * @run main/othervm SocksV4Test
*/
+import java.io.IOException;
import java.net.*;
public class SocksV4Test {
// An unresolvable host
static final String HOSTNAME = "doesnot.exist.invalid";
+ static final String USER = "johndoe";
+ static final String PASSWORD = "helloworld";
public static void main(String[] args) throws Exception {
+ Authenticator.setDefault(new Auth());
+ UHETest();
+ getLocalPortTest();
+ }
+
+ static class Auth extends Authenticator {
+ protected PasswordAuthentication getPasswordAuthentication() {
+ return new PasswordAuthentication(USER, PASSWORD.toCharArray());
+ }
+ }
+
+ public static void getLocalPortTest() throws Exception {
+ // We actually use V5 for this test because that is the default
+ // protocol version used by the client and it doesn't really handle
+ // down grading very well.
+ try (SocksServer srvr = new SocksServer(0, false);
+ ServerSocket ss = new ServerSocket(0)) {
+
+ srvr.addUser(USER, PASSWORD);
+ int serverPort = ss.getLocalPort();
+ srvr.start();
+ int proxyPort = srvr.getPort();
+ System.out.printf("Server port %d, Proxy port %d\n", serverPort, proxyPort);
+ Proxy sp = new Proxy(Proxy.Type.SOCKS,
+ new InetSocketAddress("localhost", proxyPort));
+ // Let's create an unresolved address
+ InetSocketAddress ad = new InetSocketAddress("127.0.0.1", serverPort);
+ try (Socket s = new Socket(sp)) {
+ s.connect(ad, 10000);
+ int pp = s.getLocalPort();
+ System.out.println("Local port = " + pp);
+ if (pp == serverPort || pp == proxyPort)
+ throw new RuntimeException("wrong port returned");
+ } catch (UnknownHostException ex) {
+ throw new RuntimeException(ex);
+ } catch (IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+ }
+ }
+
+ public static void UHETest() throws Exception {
// sanity before running the test
assertUnresolvableHost(HOSTNAME);
// Create a SOCKS V4 proxy
- SocksServer srvr = new SocksServer(0, true);
- srvr.start();
- Proxy sp = new Proxy(Proxy.Type.SOCKS,
- new InetSocketAddress("localhost", srvr.getPort()));
- // Let's create an unresolved address
- InetSocketAddress ad = new InetSocketAddress(HOSTNAME, 1234);
- try (Socket s = new Socket(sp)) {
- s.connect(ad, 10000);
- } catch (UnknownHostException ex) {
- // OK, that's what we expected
- } catch (NullPointerException npe) {
- // Not OK, this used to be the bug
- throw new RuntimeException("Got a NUllPointerException");
- } finally {
- srvr.terminate();
+ try (SocksServer srvr = new SocksServer(0, true)) {
+ srvr.start();
+ Proxy sp = new Proxy(Proxy.Type.SOCKS,
+ new InetSocketAddress("localhost", srvr.getPort()));
+ // Let's create an unresolved address
+ InetSocketAddress ad = new InetSocketAddress(HOSTNAME, 1234);
+ try (Socket s = new Socket(sp)) {
+ s.connect(ad, 10000);
+ } catch (UnknownHostException ex) {
+ // OK, that's what we expected
+ } catch (NullPointerException npe) {
+ // Not OK, this used to be the bug
+ throw new RuntimeException("Got a NUllPointerException");
+ }
}
}
--- a/test/jdk/sun/net/www/protocol/http/ProxyTunnelServer.java Tue Jan 22 15:33:34 2019 +0800
+++ b/test/jdk/sun/net/www/protocol/http/ProxyTunnelServer.java Thu Jan 24 15:48:05 2019 +0000
@@ -38,33 +38,40 @@
public class ProxyTunnelServer extends Thread {
- private static ServerSocket ss = null;
+ private final ServerSocket ss;
/*
* holds the registered user's username and password
* only one such entry is maintained
*/
- private String userPlusPass;
+ private volatile String userPlusPass;
// client requesting for a tunnel
- private Socket clientSocket = null;
+ private volatile Socket clientSocket = null;
/*
* Origin server's address and port that the client
* wants to establish the tunnel for communication.
*/
- private InetAddress serverInetAddr;
- private int serverPort;
+ private volatile InetAddress serverInetAddr;
+ private volatile int serverPort;
/*
* denote whether the proxy needs to authorize
* CONNECT requests.
*/
- static boolean needAuth = false;
+
+ volatile boolean needAuth = false;
public ProxyTunnelServer() throws IOException {
- if (ss == null) {
- ss = (ServerSocket) ServerSocketFactory.getDefault().
- createServerSocket(0);
+ ss = new ServerSocket(0);
+ }
+
+ static private void close(Closeable c) {
+ try {
+ if (c != null)
+ c.close();
+ } catch (IOException e) {
+ e.printStackTrace();
}
}
@@ -72,6 +79,11 @@
needAuth = auth;
}
+ public void terminate() {
+ close(ss);
+ close(clientSocket);
+ }
+
/*
* register users with the proxy, by providing username and
* password. The username and password are used for authorizing the
@@ -81,10 +93,16 @@
userPlusPass = uname + ":" + passwd;
}
+ volatile boolean makeTunnel;
+
+ public void doTunnel(boolean tunnel) {
+ makeTunnel = tunnel;
+ }
+
public void run() {
try {
clientSocket = ss.accept();
- processRequests();
+ processRequests(makeTunnel);
} catch (Exception e) {
System.out.println("Proxy Failed: " + e);
e.printStackTrace();
@@ -105,7 +123,7 @@
* if there is a match, connection is set in tunneling mode. If
* needAuth is set to false, Proxy-Authorization checks are not made
*/
- private void processRequests() throws Exception {
+ private void processRequests(boolean makeTunnel) throws Exception {
InputStream in = clientSocket.getInputStream();
MessageHeader mheader = new MessageHeader(in);
@@ -125,6 +143,13 @@
}
}
}
+
+ if (makeTunnel) {
+ retrieveConnectInfo(statusLine);
+ doTunnel();
+ return;
+ }
+
respondForConnect(needAuth);
// connection set to the tunneling mode
@@ -178,6 +203,9 @@
* direction.
*/
private void doTunnel() throws Exception {
+ OutputStream out = clientSocket.getOutputStream();
+ out.write("HTTP/1.1 200 OK\r\n\r\n".getBytes());
+ out.flush();
Socket serverSocket = new Socket(serverInetAddr, serverPort);
ProxyTunnel clientToServer = new ProxyTunnel(
@@ -202,10 +230,10 @@
* socket, until both sockets are open and EOF has not been received.
*/
class ProxyTunnel extends Thread {
- Socket sockIn;
- Socket sockOut;
- InputStream input;
- OutputStream output;
+ final Socket sockIn;
+ final Socket sockOut;
+ final InputStream input;
+ final OutputStream output;
public ProxyTunnel(Socket sockIn, Socket sockOut)
throws Exception {
--- a/test/jdk/sun/net/www/protocol/http/TunnelThroughProxy.java Tue Jan 22 15:33:34 2019 +0800
+++ b/test/jdk/sun/net/www/protocol/http/TunnelThroughProxy.java Thu Jan 24 15:48:05 2019 +0000
@@ -25,6 +25,7 @@
* @test
* @bug 4620362
* @modules java.base/sun.net.www
+ * @build ProxyTunnelServer
* @run main/othervm TunnelThroughProxy
* @summary JSSE not returning proper exception on unknown host
*/
@@ -34,8 +35,13 @@
public class TunnelThroughProxy {
public static void main(String[] args) throws Exception {
+ nonexistingHostTest();
+ getLocalPortTest();
+ }
+
+ static void nonexistingHostTest() throws Exception {
+ ProxyTunnelServer proxy = setupProxy(false);
try {
- setupProxy();
URL u = new URL("https://www.nonexistent-site.com/");
URLConnection uc = u.openConnection();
InputStream is = uc.getInputStream();
@@ -44,16 +50,48 @@
if (!e.getMessage().matches(".*HTTP\\/.*500.*")) {
throw new RuntimeException(e);
}
+ } finally {
+ proxy.terminate();
}
}
- static void setupProxy() throws IOException {
+
+
+ static void getLocalPortTest() throws Exception {
+ ProxyTunnelServer proxy = setupProxy(true);
+ try {
+ int proxyPort = proxy.getPort();
+ ServerSocket server = new ServerSocket(0);
+ int serverPort = server.getLocalPort();
+
+ Socket sock;
+ sock = new Socket(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", proxyPort)));
+ InetSocketAddress dest = new InetSocketAddress("127.0.0.1", serverPort);
+ sock.connect(dest);
+ int localPort = sock.getLocalPort();
+ if (localPort == proxyPort)
+ throw new RuntimeException("Fail: socket has wrong local port");
+ // check that tunnel really works
+ Socket sock1 = server.accept();
+ OutputStream os = sock1.getOutputStream();
+ os.write(99);
+ os.flush();
+ if (sock.getInputStream().read() != 99)
+ throw new RuntimeException("Tunnel does not work");
+ } finally {
+ proxy.terminate();
+ }
+ }
+
+ static ProxyTunnelServer setupProxy(boolean makeTunnel) throws IOException {
ProxyTunnelServer pserver = new ProxyTunnelServer();
+ pserver.doTunnel(makeTunnel);
+ int proxyPort = pserver.getPort();
// disable proxy authentication
pserver.needUserAuth(false);
pserver.start();
System.setProperty("https.proxyHost", "localhost");
- System.setProperty("https.proxyPort", String.valueOf(
- pserver.getPort()));
+ System.setProperty("https.proxyPort", String.valueOf(proxyPort));
+ return pserver;
}
}