8220663: Incorrect handling of IPv6 addresses in Socket(Proxy.HTTP)

Reviewed-by: alanb, michaelm
This commit is contained in:
Chris Hegarty 2019-03-19 14:27:50 +00:00
parent 3b0ae8082a
commit 5ee0711360
2 changed files with 79 additions and 34 deletions

View File

@ -114,7 +114,7 @@ import java.util.Set;
if (endpoint == null || !(endpoint instanceof InetSocketAddress)) if (endpoint == null || !(endpoint instanceof InetSocketAddress))
throw new IllegalArgumentException("Unsupported address type"); throw new IllegalArgumentException("Unsupported address type");
final InetSocketAddress epoint = (InetSocketAddress)endpoint; final InetSocketAddress epoint = (InetSocketAddress)endpoint;
final String destHost = epoint.isUnresolved() ? epoint.getHostName() String destHost = epoint.isUnresolved() ? epoint.getHostName()
: epoint.getAddress().getHostAddress(); : epoint.getAddress().getHostAddress();
final int destPort = epoint.getPort(); final int destPort = epoint.getPort();
@ -122,6 +122,9 @@ import java.util.Set;
if (security != null) if (security != null)
security.checkConnect(destHost, destPort); security.checkConnect(destHost, destPort);
if (destHost.contains(":"))
destHost = "[" + destHost + "]";
// Connect to the HTTP proxy server // Connect to the HTTP proxy server
String urlString = "http://" + destHost + ":" + destPort; String urlString = "http://" + destHost + ":" + destPort;
Socket httpSocket = privilegedDoTunnel(urlString, timeout); Socket httpSocket = privilegedDoTunnel(urlString, timeout);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -23,11 +23,12 @@
/* /*
* @test * @test
* @bug 6370908 * @bug 6370908 8220663
* @summary Add support for HTTP_CONNECT proxy in Socket class * @summary Add support for HTTP_CONNECT proxy in Socket class
* @modules java.base/sun.net.www * @modules java.base/sun.net.www
* @run main HttpProxy * @run main HttpProxy
* @run main/othervm -Djava.net.preferIPv4Stack=true HttpProxy * @run main/othervm -Djava.net.preferIPv4Stack=true HttpProxy
* @run main/othervm -Djava.net.preferIPv6Addresses=true HttpProxy
*/ */
import java.io.IOException; import java.io.IOException;
@ -40,6 +41,9 @@ import java.net.InetSocketAddress;
import java.net.Proxy; import java.net.Proxy;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.List;
import sun.net.www.MessageHeader; import sun.net.www.MessageHeader;
public class HttpProxy { public class HttpProxy {
@ -50,9 +54,10 @@ public class HttpProxy {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
String host; String host;
int port; int port;
ConnectProxyTunnelServer proxy = null;
if (args.length == 0) { if (args.length == 0) {
// Start internal proxy // Start internal proxy
ConnectProxyTunnelServer proxy = new ConnectProxyTunnelServer(); proxy = new ConnectProxyTunnelServer();
proxy.start(); proxy.start();
host = "localhost"; host = "localhost";
port = proxy.getLocalPort(); port = proxy.getLocalPort();
@ -66,8 +71,13 @@ public class HttpProxy {
return; return;
} }
try {
HttpProxy p = new HttpProxy(host, port); HttpProxy p = new HttpProxy(host, port);
p.test(); p.test();
} finally {
if (proxy != null)
proxy.close();
}
} }
public HttpProxy(String proxyHost, int proxyPort) { public HttpProxy(String proxyHost, int proxyPort) {
@ -79,14 +89,23 @@ public class HttpProxy {
InetSocketAddress proxyAddress = new InetSocketAddress(proxyHost, proxyPort); InetSocketAddress proxyAddress = new InetSocketAddress(proxyHost, proxyPort);
Proxy httpProxy = new Proxy(Proxy.Type.HTTP, proxyAddress); Proxy httpProxy = new Proxy(Proxy.Type.HTTP, proxyAddress);
try (ServerSocket ss = new ServerSocket(0); try (ServerSocket ss = new ServerSocket(0)) {
Socket sock = new Socket(httpProxy)) { List<InetSocketAddress> externalAddresses = new ArrayList<>();
externalAddresses.add(
new InetSocketAddress(InetAddress.getLocalHost(), ss.getLocalPort()));
if (!"true".equals(System.getProperty("java.net.preferIPv4Stack"))) {
byte[] bytes = new byte[] {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
var address = InetAddress.getByAddress(bytes);
externalAddresses.add(
new InetSocketAddress(address, ss.getLocalPort()));
}
for (SocketAddress externalAddress : externalAddresses) {
try (Socket sock = new Socket(httpProxy)) {
sock.setSoTimeout(SO_TIMEOUT); sock.setSoTimeout(SO_TIMEOUT);
sock.setTcpNoDelay(false); sock.setTcpNoDelay(false);
InetSocketAddress externalAddress =
new InetSocketAddress(InetAddress.getLocalHost(), ss.getLocalPort());
out.println("Trying to connect to server socket on " + externalAddress); out.println("Trying to connect to server socket on " + externalAddress);
sock.connect(externalAddress); sock.connect(externalAddress);
try (Socket externalSock = ss.accept()) { try (Socket externalSock = ss.accept()) {
@ -102,13 +121,15 @@ public class HttpProxy {
} }
} }
} }
}
}
static void check(boolean condition, String message) { static void check(boolean condition, String message) {
if (!condition) out.println(message); if (!condition) out.println(message);
} }
static Exception unexpected(Exception e) { static Exception unexpected(Exception e) {
out.println("Unexcepted Exception: " + e); out.println("Unexpected Exception: " + e);
e.printStackTrace(); e.printStackTrace();
return e; return e;
} }
@ -164,9 +185,10 @@ public class HttpProxy {
return i1 * 256 + i2; return i1 * 256 + i2;
} }
static class ConnectProxyTunnelServer extends Thread { static class ConnectProxyTunnelServer extends Thread implements AutoCloseable {
private final ServerSocket ss; private final ServerSocket ss;
private volatile boolean closed;
public ConnectProxyTunnelServer() throws IOException { public ConnectProxyTunnelServer() throws IOException {
ss = new ServerSocket(0); ss = new ServerSocket(0);
@ -174,12 +196,19 @@ public class HttpProxy {
@Override @Override
public void run() { public void run() {
try {
while (!closed) {
try (Socket clientSocket = ss.accept()) { try (Socket clientSocket = ss.accept()) {
processRequest(clientSocket); processRequest(clientSocket);
}
}
} catch (Exception e) { } catch (Exception e) {
if (!closed) {
out.println("Proxy Failed: " + e); out.println("Proxy Failed: " + e);
e.printStackTrace(); e.printStackTrace();
}
} finally { } finally {
if (!closed)
try { ss.close(); } catch (IOException x) { unexpected(x); } try { ss.close(); } catch (IOException x) { unexpected(x); }
} }
} }
@ -191,6 +220,12 @@ public class HttpProxy {
return ss.getLocalPort(); return ss.getLocalPort();
} }
@Override
public void close() throws Exception {
closed = true;
ss.close();
}
/* /*
* Processes the CONNECT request * Processes the CONNECT request
*/ */
@ -200,7 +235,7 @@ public class HttpProxy {
if (!statusLine.startsWith("CONNECT")) { if (!statusLine.startsWith("CONNECT")) {
out.println("proxy server: processes only " out.println("proxy server: processes only "
+ "CONNECT method requests, recieved: " + "CONNECT method requests, received: "
+ statusLine); + statusLine);
return; return;
} }
@ -246,12 +281,19 @@ public class HttpProxy {
int endi = connectStr.lastIndexOf(' '); int endi = connectStr.lastIndexOf(' ');
String connectInfo = connectStr.substring(starti+1, endi).trim(); String connectInfo = connectStr.substring(starti+1, endi).trim();
// retrieve server name and port // retrieve server name and port
endi = connectInfo.indexOf(':'); endi = connectInfo.lastIndexOf(':');
String name = connectInfo.substring(0, endi); String name = connectInfo.substring(0, endi);
if (name.contains(":")) {
if (!(name.startsWith("[") && name.endsWith("]"))) {
throw new IOException("Invalid host:" + name);
}
name = name.substring(1, name.length() - 1);
}
int port = Integer.parseInt(connectInfo.substring(endi+1)); int port = Integer.parseInt(connectInfo.substring(endi+1));
return new InetSocketAddress(name, port); return new InetSocketAddress(name, port);
} catch (Exception e) { } catch (Exception e) {
out.println("Proxy recieved a request: " + connectStr); out.println("Proxy received a request: " + connectStr);
throw unexpected(e); throw unexpected(e);
} }
} }