简体   繁体   English

通过Java中的HTTP代理创建TLS连接

[英]Creating a TLS connection through an HTTP proxy in Java

I'm working on getting a service connected through a TLS connection in Java. 我正在尝试通过Java中的TLS连接来连接服务。 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. 我找到了一些非常简单的代码来处理并以这种方式实现-这不是真正的IP,但端口为8080。此外,我也不会保留IP的硬编码,这只是出于测试目的。

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 这段代码会思考很长时间,最终会引发另一个异常-javax.net.ssl.SSLHandshakeException:握手期间远程主机关闭连接

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? javax.net.ssl.SSLException:无法识别的SSL消息,纯文本连接?

So it looks like it's trying to use TLS to go through the proxy port 8080 and failing. 因此,似乎正在尝试使用TLS通过代理端口8080并失败。 Also, there is no HTTPS port for me to go through, all others refuse the connection. 另外,我没有HTTPS端口可以通过,其他所有端口都拒绝连接。

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. 如果您在状态行之后有更多标头,即使是响应CONNECT请求,我也不会感到惊讶。 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. 当然,更多的标头肯定会导致Unrecognized SSL message, plaintext connection错误。

  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. 同样,为了获得更大的灵活性,我不会寻找确切的原因短语,而只是寻找状态代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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