Добрый день!
Подскажите пожалуйста, у меня такая ситуация, написал свой HTTP\HTTPS прокси-сервер, добавил слушающий порт на адресе 127.0.0.1:8080 в системные настройки прокси Windows. Соответственно этот прокси по умолчанию используют IE, Chrome и Opera, только в FF надо прописывать его вручную. Сразу оговорюсь, HTTP работает нормально, а вот с HTTPS проблема. Кратко опишу алгоритм моих действий:
Создаю слушающий сокет
В цикле дожидаюсь коннекта от браузера
Акцептирую коннект
Создаю новый поток и передаю ему новый сокет в качестве параметра
Принимаю в блокирующем режиме данные с браузера
CONNECT example.com:443 HTTP/1.1
Host: example.com:443
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36
Парсю этот пакет и вытаскиваю из него имя хоста и порт
Создаю новый сокет и соединяюсь с этим сервером
Отсылаю браузеру ответ
HTTP/1.1 200 Connection Established
Перевожу два соединения в неблокирующий режим
Начинаю гонять пакеты между брайзером и веб-сервером, при этом в зашифрованные данные не лезу, просто передаю пакеты от браузера к серверу и обратно.
Вся проблема в том, что когда я отсылаю браузеру ответ
HTTP/1.1 200 Connection Established\r\n\r\n, то он обрывает соединение, а Chrome в частности выдает эту ошибку — ERR_TUNNEL_CONNECTION_FAILED. Думал может что с системой, но поставил тот же SmallProxy и он отлично работает. Смотрел сниффером его ответ, он передает то же самое что и я. Подскажите из-за чего браузер рвет коннект. Зараннее спасбо за помощь!
DWORD WINAPI session_thread(LPVOID session_connect)
{
client_struct *conn = session_connect;
request_struct *request = NULL;
response_struct *response = NULL;
proxy_struct *proxy = NULL;
fd_set read_fds;
LPVOID proxy_buffer = NULL;
LPVOID request_buffer = NULL;
LPVOID response_buffer = NULL;
DWORD dwResult = 0;
LONG from_timeout = BROWSER_TIMEOUT;
LONG to_timeout = SERVER_TIMEOUT;
LONG nbio = TRUE;
LONG nRead = 0;
LONG nSent = 0;
LONG nProxySize = 0;
LONG nReqSize = 0;
LONG nRespSize = 0;
BOOL bFlag = FALSE;
BOOL is_ssl = FALSE;
CHAR from_buff[MAX_PACKET_SIZE];
CHAR to_buff[MAX_PACKET_SIZE];
CHAR szResponse[] = "HTTP/1.1 200 Connection Established\r\n\r\n";
if (setsockopt(conn->fsock, SOL_SOCKET, SO_RCVTIMEO, (PCHAR)&from_timeout, sizeof(LONG)))
{
goto cleanup;
}
ZeroMemory(&from_buff, sizeof(from_buff));
do
{
nRead = recv(conn->fsock, &from_buff, MAX_PACKET_SIZE, 0);
if (nRead > 0)
{
if (!bFlag)
{
proxy_buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nRead);
if (proxy_buffer == NULL)
{
goto cleanup;
}
bFlag = TRUE;
}
else
{
proxy_buffer = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, proxy_buffer, nRead + nProxySize);
if (proxy_buffer == NULL)
{
goto cleanup;
}
}
CopyMemory(proxy_buffer + nProxySize, &from_buff, nRead);
nProxySize = nProxySize + nRead;
}
} while (nRead > 0);
if (nRead)
{
proxy = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(proxy_struct));
proxy->header = proxy_buffer;
proxy->header_size = nProxySize;
dwResult = proxy_handler(proxy);
if (!dwResult)
{
goto cleanup;
}
}
else
{
goto cleanup;
}
CopyMemory(&conn->to, &proxy->sa, sizeof(struct sockaddr_in));
if ((conn->tsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
{
goto cleanup;
}
if (connect(conn->tsock, (struct sockaddr*)&conn->to, sizeof(struct sockaddr_in)) == SOCKET_ERROR)
{
goto cleanup;
}
if (ntohs(conn->to.sin_port)%2 != 0)
{
is_ssl = TRUE;
}
if (is_ssl)
{
send(conn->fsock, &szResponse, sizeof(szResponse), 0);
}
else
{
send(conn->tsock, proxy_buffer, nProxySize, 0);
}
if (ioctlsocket(conn->tsock, FIONBIO, &nbio) == SOCKET_ERROR)
{
goto cleanup;
}
if (ioctlsocket(conn->fsock, FIONBIO, &nbio) == SOCKET_ERROR)
{
goto cleanup;
}
for (;;)
{
FD_ZERO(&read_fds);
FD_SET(conn->tsock, &read_fds);
FD_SET(conn->fsock, &read_fds);
if (select(0, &read_fds, NULL, NULL, NULL) == SOCKET_ERROR)
{
goto cleanup;
}
if (FD_ISSET(conn->fsock, &read_fds))
{
if ((nRead = recv(conn->fsock, &from_buff, MAX_PACKET_SIZE, 0)) > 0)
{
nSent = send(conn->tsock, &from_buff, nRead, 0);
if (nSent < 0 && ((WSAGetLastError() != WSAEWOULDBLOCK)))
{
goto cleanup;
}
}
else
{
goto cleanup;
}
}
if (FD_ISSET(conn->tsock, &read_fds))
{
if ((nRead = recv(conn->tsock, &to_buff, MAX_PACKET_SIZE, 0)) > 0)
{
nSent = send(conn->fsock, &to_buff, nRead, 0);
if (nSent < 0 && ((WSAGetLastError() != WSAEWOULDBLOCK)))
{
goto cleanup;
}
}
else
{
goto cleanup;
}
}
}
cleanup:
if (conn->fsock) shutdown(conn->fsock, SD_BOTH);
if (conn->fsock) closesocket(conn->fsock);
if (conn->tsock) shutdown(conn->tsock, SD_BOTH);
if (conn->tsock) closesocket(conn->tsock);
if (request_buffer) HeapFree(GetProcessHeap(), 0, request_buffer);
if (response_buffer) HeapFree(GetProcessHeap(), 0, response_buffer);
if (proxy_buffer) HeapFree(GetProcessHeap(), 0, proxy_buffer);
if (request) HeapFree(GetProcessHeap(), 0, request);
if (response) HeapFree(GetProcessHeap(), 0, response);
if (proxy) HeapFree(GetProcessHeap(), 0, proxy);
if (session_connect) HeapFree(GetProcessHeap(), 0, session_connect);
return 0;
}