简体   繁体   中英

Creating a TLS connection through an HTTP proxy in Java

I'm working on getting a service connected through a TLS connection in Java. I am able to get the service connected and get a response in one environment, but can't seem to get through in another which uses a firewall and proxy server. In this environment my application was trying to go straight through the firewall and returning an unknown host exception.

I found some pretty simple code to handle this and implemented it in this way - This isn't the real IP, but the port is 8080. Also, I'm not going to leave the IP hardcoded, this is just for testing purposes.

String tunnelHost = "111.11.11.11";
int tunnelPort = 8080;
Socket proxyTunnel = new Socket(InetAddress.getByName(tunnelHost), tunnelPort);
socket = (SSLSocket)factory.createSocket(proxyTunnel, path.getHost(), path.getPort(), true);

This code would think for a long time and end up throwing another exception - javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake

I found that the code wasn't even reaching the proxy server, so I tried to implement a "Tunnel Handshake" from some code I had been seeing online, making the full code -

String tunnelHost = "111.11.11.11";
int tunnelPort = 8080;
Socket proxyTunnel = new Socket(InetAddress.getByName(tunnelHost), tunnelPort);
doTunnelHandshake(proxyTunnel, path.getHost(), path.getPort());
try {
    socket = (SSLSocket)factory.createSocket(proxyTunnel, path.getHost(), path.getPort(), true);
} catch(IOException e) {
    e.printStackTrace();
}

public void doTunnelHandshake(Socket tunnel, String host, int port) throws IOException {
    OutputStream out = tunnel.getOutputStream();  
    String msg = "CONNECT " + host + ":" + port + " HTTP/1.0\n"  
            + "User-Agent: "  
            + sun.net.www.protocol.http.HttpURLConnection.userAgent  
            + "\r\n\r\n";  
    byte b[];  
    try {  
        b = msg.getBytes("ASCII7");  
    } catch (UnsupportedEncodingException ignored) {  
        b = msg.getBytes();  
    }  
    out.write(b);  
    out.flush();  
    byte reply[] = new byte[200];  
    int replyLen = 0;  
    int newlinesSeen = 0;  
    boolean headerDone = false;     /* Done on first newline */  
    InputStream in = tunnel.getInputStream();
    try {
        while (newlinesSeen < 2) {
            int i = in.read();  
            if (i < 0) {  
                throw new IOException("Unexpected EOF from proxy");  
            }  
            if (i == '\n') {  
                headerDone = true;  
                ++newlinesSeen;  
            } else if (i != '\r') {  
                newlinesSeen = 0;  
                if (!headerDone && replyLen < reply.length) {  
                    reply[replyLen++] = (byte) i;  
                }
            }
        }
        String replyStr;
        try {
            replyStr = new String(reply, 0, replyLen, "ASCII7");
        } catch (UnsupportedEncodingException ignored) {
            replyStr = new String(reply, 0, replyLen);
        }
        if(replyStr.toLowerCase().indexOf(
                "200 connection established") == -1) {
        throw new IOException("Unable to tunnel through proxy."
                + " Proxy returns \"" + replyStr + "\"");
        }
    } catch (Exception e) {
        e.printStackTrace();
        log.fine("Tunnel Handshake Failed");
    }
    log.finer("Tunnel Handshake Completed");
}

This code gave me another error

javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?

So it looks like it's trying to use TLS to go through the proxy port 8080 and failing. Also, there is no HTTPS port for me to go through, all others refuse the connection.

I've looked in quite a few places online in researching this problem and haven't found any solution yet, does anybody have any suggestions on how to get this working through the proxy?

while (newlinesSeen < 2) {

I wouldn't be surprised if you had more headers after the status line, even in response to a CONNECT request. You should probably try to detect the end of the headers (which is the end of the response in this case) more flexibly, as described here , instead of counting the number of new lines.

More headers would certainly cause an Unrecognized SSL message, plaintext connection error at this stage.

  if(replyStr.toLowerCase().indexOf( "200 connection established") == -1) { 

Again, for more flexibility, I wouldn't look for the exact reason phrase, just for the status code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM