Я пытаюсь использовать Java (Android) для подключения к серверу с помощью сокета SSL. Обратите внимание, что это не HTTP-данные. Это проприетарный протокол с сочетанием текстовых и двоичных данных.
Я хочу передать это SSL-соединение через HTTP-прокси, но перед этим сталкиваюсь с множеством проблем. Прямо сейчас сценарий, который я использую и что мой браузер, похоже, использует с прокси-сервером squid, как следует
[client] → [http connection] → [proxy] → [ssl connection] → [server]
Это работает для браузера, потому что после того, как прокси делает соединение ssl, переговоры TLS происходят немедленно. Однако мой код, похоже, не делает этого.
final TrustManager[] trustManager = new TrustManager[] { new MyX509TrustManager() };
final SSLContext context = SSLContext.getInstance("TLS");
context.init(null, trustManager, null);
SSLSocketFactory factory = context.getSocketFactory();
Socket s = factory.createSocket(new Socket(proxy_ip, 3128), hostName, port, true);
Проблема, которая у меня есть, заключается в том, что createSocket NEVER RETURNS. С дампом wirehark от прокси-машины я вижу, что между прокси-сервером и сервером происходит рукопожатие tcp. С дампами веб-сессий я вижу, что клиент обычно инициирует SSL-квитирование в этот момент, чего не происходит в моем сценарии.
Это не проблема с менеджером доверия, потому что сертификат никогда не возвращается ко мне, и он никогда не проверяется.
ИЗМЕНИТЬ:
После обсуждения это более полная версия кода, который я пытаюсь запустить. Эта версия выше с простым (новый Socket (...)) как параметр - это то, что я пробовал позже.
Оригинальная версия кода, который я пытаюсь отлаживать броски java.net.ConnectException: failed to connect to /192.168.1.100 (port 443): connect failed: ETIMEDOUT (Connection timed out)
Последовательность следующая (немного упрощенная):
final Socket proxySocket = new Socket();
proxySocket.connect(proxyAddress, 2000); // 2 seconds as the connection timeout for connecting to the proxy server
[Start a thread and write to outputStream=socket.getOutputStream()]
final String proxyRequest = String.format("CONNECT %s:%d HTTP/1.1\r\nProxy-Connection: keep-alive\r\nConnection: keep-alive\r\nHost: %s:%d\r\n\r\n", hostName, port, hostName, port);
outputStream.close(); // Closing or not doesn't change anything
[Stop using that thread and let it exit by reaching the end of its main function]
Затем прочитайте ответ со следующим кодом:
final InputStreamReader isr = new InputStreamReader(proxySocket.getInputStream());
final BufferedReader br = new BufferedReader(isr);
final String statusLine = br.readLine();
boolean proxyConnectSuccess = false;
// readLine consumed the CRLF
final Pattern statusLinePattern = Pattern.compile("^HTTP/\\d+\\.\\d+ (\\d\\d\\d) .*");
final Matcher statusLineMatcher = statusLinePattern.matcher(statusLine);
if (statusLineMatcher.matches())
{
final String statusCode = statusLineMatcher.group(1);
if (null != statusCode && 0 < statusCode.length() && '2' == statusCode.charAt(0))
{
proxyConnectSuccess = true;
}
}
// Consume rest of proxy response
String line;
while ( "".equals((line = br.readLine())) == false )
{
}
Я могу сказать, что этот код работает, потому что он работает без SSL. Созданный здесь сокет proxySocket
- это тот, который передается функции createSocket, а не просто создает новый "на лету", как в моем первоначальном примере.