[core,proxy] fix nonblocking BIO reads

* In case of non-blocking BIO layers the proxy read functions bailed
  out with an error. Retry reading in that case unless the
  TcpConnectTimeout is exceeded
* Terminate proxy read operations if rdpContext::abortEvent is set
This commit is contained in:
akallabeth 2024-09-17 10:26:55 +02:00
parent 6c88d89566
commit c7efbf5b8e
No known key found for this signature in database
GPG Key ID: A49454A3FC909FD5
7 changed files with 61 additions and 20 deletions

View File

@ -124,7 +124,7 @@ static BOOL arm_tls_connect(rdpArm* arm, rdpTls* tls, int timeout)
if (isProxyConnection) if (isProxyConnection)
{ {
if (!proxy_connect(settings, bufferedBio, proxyUsername, proxyPassword, if (!proxy_connect(arm->context, bufferedBio, proxyUsername, proxyPassword,
freerdp_settings_get_string(settings, FreeRDP_GatewayHostname), freerdp_settings_get_string(settings, FreeRDP_GatewayHostname),
(UINT16)freerdp_settings_get_uint32(settings, FreeRDP_GatewayPort))) (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_GatewayPort)))
{ {

View File

@ -1301,7 +1301,7 @@ static BOOL rdg_tls_connect(rdpRdg* rdg, rdpTls* tls, const char* peerAddress, i
if (isProxyConnection) if (isProxyConnection)
{ {
if (!proxy_connect(settings, bufferedBio, proxyUsername, proxyPassword, if (!proxy_connect(rdg->context, bufferedBio, proxyUsername, proxyPassword,
settings->GatewayHostname, (UINT16)settings->GatewayPort)) settings->GatewayHostname, (UINT16)settings->GatewayPort))
{ {
BIO_free_all(bufferedBio); BIO_free_all(bufferedBio);

View File

@ -759,7 +759,7 @@ static BOOL rpc_channel_tls_connect(RpcChannel* channel, UINT32 timeout)
if (channel->client->isProxy) if (channel->client->isProxy)
{ {
if (!proxy_connect(settings, bufferedBio, proxyUsername, proxyPassword, if (!proxy_connect(context, bufferedBio, proxyUsername, proxyPassword,
settings->GatewayHostname, settings->GatewayPort)) settings->GatewayHostname, settings->GatewayPort))
{ {
BIO_free_all(bufferedBio); BIO_free_all(bufferedBio);

View File

@ -254,7 +254,7 @@ static BOOL wst_tls_connect(rdpWst* wst, rdpTls* tls, int timeout)
if (isProxyConnection) if (isProxyConnection)
{ {
if (!proxy_connect(settings, bufferedBio, proxyUsername, proxyPassword, wst->gwhostname, if (!proxy_connect(wst->context, bufferedBio, proxyUsername, proxyPassword, wst->gwhostname,
wst->gwport)) wst->gwport))
{ {
BIO_free_all(bufferedBio); BIO_free_all(bufferedBio);

View File

@ -30,6 +30,7 @@
#include "tcp.h" #include "tcp.h"
#include <winpr/assert.h> #include <winpr/assert.h>
#include <winpr/sysinfo.h>
#include <winpr/environment.h> /* For GetEnvironmentVariableA */ #include <winpr/environment.h> /* For GetEnvironmentVariableA */
#define CRLF "\r\n" #define CRLF "\r\n"
@ -70,9 +71,9 @@ static const char* rplstat[] = { "succeeded",
"Command not supported", "Command not supported",
"Address type not supported" }; "Address type not supported" };
static BOOL http_proxy_connect(BIO* bufferedBio, const char* proxyUsername, static BOOL http_proxy_connect(rdpContext* context, BIO* bufferedBio, const char* proxyUsername,
const char* proxyPassword, const char* hostname, UINT16 port); const char* proxyPassword, const char* hostname, UINT16 port);
static BOOL socks_proxy_connect(BIO* bufferedBio, const char* proxyUsername, static BOOL socks_proxy_connect(rdpContext* context, BIO* bufferedBio, const char* proxyUsername,
const char* proxyPassword, const char* hostname, UINT16 port); const char* proxyPassword, const char* hostname, UINT16 port);
static void proxy_read_environment(rdpSettings* settings, char* envname); static void proxy_read_environment(rdpSettings* settings, char* envname);
@ -483,9 +484,12 @@ fail:
return rc; return rc;
} }
BOOL proxy_connect(rdpSettings* settings, BIO* bufferedBio, const char* proxyUsername, BOOL proxy_connect(rdpContext* context, BIO* bufferedBio, const char* proxyUsername,
const char* proxyPassword, const char* hostname, UINT16 port) const char* proxyPassword, const char* hostname, UINT16 port)
{ {
WINPR_ASSERT(context);
rdpSettings* settings = context->settings;
switch (freerdp_settings_get_uint32(settings, FreeRDP_ProxyType)) switch (freerdp_settings_get_uint32(settings, FreeRDP_ProxyType))
{ {
case PROXY_TYPE_NONE: case PROXY_TYPE_NONE:
@ -493,10 +497,12 @@ BOOL proxy_connect(rdpSettings* settings, BIO* bufferedBio, const char* proxyUse
return TRUE; return TRUE;
case PROXY_TYPE_HTTP: case PROXY_TYPE_HTTP:
return http_proxy_connect(bufferedBio, proxyUsername, proxyPassword, hostname, port); return http_proxy_connect(context, bufferedBio, proxyUsername, proxyPassword, hostname,
port);
case PROXY_TYPE_SOCKS: case PROXY_TYPE_SOCKS:
return socks_proxy_connect(bufferedBio, proxyUsername, proxyPassword, hostname, port); return socks_proxy_connect(context, bufferedBio, proxyUsername, proxyPassword, hostname,
port);
default: default:
WLog_ERR(TAG, "Invalid internal proxy configuration"); WLog_ERR(TAG, "Invalid internal proxy configuration");
@ -516,7 +522,7 @@ static const char* get_response_header(char* response)
return response; return response;
} }
static BOOL http_proxy_connect(BIO* bufferedBio, const char* proxyUsername, static BOOL http_proxy_connect(rdpContext* context, BIO* bufferedBio, const char* proxyUsername,
const char* proxyPassword, const char* hostname, UINT16 port) const char* proxyPassword, const char* hostname, UINT16 port)
{ {
BOOL rc = FALSE; BOOL rc = FALSE;
@ -532,8 +538,11 @@ static BOOL http_proxy_connect(BIO* bufferedBio, const char* proxyUsername,
const char connect[] = "CONNECT "; const char connect[] = "CONNECT ";
const char httpheader[] = " HTTP/1.1" CRLF "Host: "; const char httpheader[] = " HTTP/1.1" CRLF "Host: ";
WINPR_ASSERT(context);
WINPR_ASSERT(bufferedBio); WINPR_ASSERT(bufferedBio);
WINPR_ASSERT(hostname); WINPR_ASSERT(hostname);
const UINT32 timeout =
freerdp_settings_get_uint32(context->settings, FreeRDP_TcpConnectTimeout);
_itoa_s(port, port_str, sizeof(port_str), 10); _itoa_s(port, port_str, sizeof(port_str), 10);
@ -601,6 +610,7 @@ static BOOL http_proxy_connect(BIO* bufferedBio, const char* proxyUsername,
/* Read result until CR-LF-CR-LF. /* Read result until CR-LF-CR-LF.
* Keep recv_buf a null-terminated string. */ * Keep recv_buf a null-terminated string. */
const UINT64 start = GetTickCount64();
while (strstr(recv_buf, CRLF CRLF) == NULL) while (strstr(recv_buf, CRLF CRLF) == NULL)
{ {
if (resultsize >= sizeof(recv_buf) - 1) if (resultsize >= sizeof(recv_buf) - 1)
@ -616,7 +626,7 @@ static BOOL http_proxy_connect(BIO* bufferedBio, const char* proxyUsername,
if (status < 0) if (status < 0)
{ {
/* Error? */ /* Error? */
if (BIO_should_retry(bufferedBio)) if (!freerdp_shall_disconnect_context(context) && BIO_should_retry(bufferedBio))
{ {
USleep(100); USleep(100);
continue; continue;
@ -626,6 +636,18 @@ static BOOL http_proxy_connect(BIO* bufferedBio, const char* proxyUsername,
goto fail; goto fail;
} }
else if (status == 0) else if (status == 0)
{
const UINT64 now = GetTickCount64();
const UINT64 diff = now - start;
if (freerdp_shall_disconnect_context(context) || (now < start) || (diff > timeout))
{
/* Error? */
WLog_ERR(TAG, "Failed reading reply from HTTP proxy (BIO_read returned zero)");
goto fail;
}
Sleep(10);
}
else
{ {
/* Error? */ /* Error? */
WLog_ERR(TAG, "Failed reading reply from HTTP proxy (BIO_read returned zero)"); WLog_ERR(TAG, "Failed reading reply from HTTP proxy (BIO_read returned zero)");
@ -661,10 +683,16 @@ fail:
return rc; return rc;
} }
static int recv_socks_reply(BIO* bufferedBio, BYTE* buf, int len, char* reason, BYTE checkVer) static int recv_socks_reply(rdpContext* context, BIO* bufferedBio, BYTE* buf, int len, char* reason,
BYTE checkVer)
{ {
int status = 0; int status = 0;
WINPR_ASSERT(context);
const UINT32 timeout =
freerdp_settings_get_uint32(context->settings, FreeRDP_TcpConnectTimeout);
const UINT64 start = GetTickCount64();
for (;;) for (;;)
{ {
ERR_clear_error(); ERR_clear_error();
@ -677,7 +705,7 @@ static int recv_socks_reply(BIO* bufferedBio, BYTE* buf, int len, char* reason,
else if (status < 0) else if (status < 0)
{ {
/* Error? */ /* Error? */
if (BIO_should_retry(bufferedBio)) if (!freerdp_shall_disconnect_context(context) && BIO_should_retry(bufferedBio))
{ {
USleep(100); USleep(100);
continue; continue;
@ -686,6 +714,19 @@ static int recv_socks_reply(BIO* bufferedBio, BYTE* buf, int len, char* reason,
WLog_ERR(TAG, "Failed reading %s reply from SOCKS proxy (Status %d)", reason, status); WLog_ERR(TAG, "Failed reading %s reply from SOCKS proxy (Status %d)", reason, status);
return -1; return -1;
} }
else if (status == 0)
{
const UINT64 now = GetTickCount64();
const UINT64 diff = now - start;
if (freerdp_shall_disconnect_context(context) || (now < start) || (diff > timeout))
{
/* Error? */
WLog_ERR(TAG, "Failed reading %s reply from SOCKS proxy (BIO_read returned zero)",
reason);
return status;
}
Sleep(10);
}
else // if (status == 0) else // if (status == 0)
{ {
/* Error? */ /* Error? */
@ -710,7 +751,7 @@ static int recv_socks_reply(BIO* bufferedBio, BYTE* buf, int len, char* reason,
return status; return status;
} }
static BOOL socks_proxy_connect(BIO* bufferedBio, const char* proxyUsername, static BOOL socks_proxy_connect(rdpContext* context, BIO* bufferedBio, const char* proxyUsername,
const char* proxyPassword, const char* hostname, UINT16 port) const char* proxyPassword, const char* hostname, UINT16 port)
{ {
int status = 0; int status = 0;
@ -742,7 +783,7 @@ static BOOL socks_proxy_connect(BIO* bufferedBio, const char* proxyUsername,
return FALSE; return FALSE;
} }
status = recv_socks_reply(bufferedBio, buf, 2, "AUTH REQ", 5); status = recv_socks_reply(context, bufferedBio, buf, 2, "AUTH REQ", 5);
if (status <= 0) if (status <= 0)
return FALSE; return FALSE;
@ -786,7 +827,7 @@ static BOOL socks_proxy_connect(BIO* bufferedBio, const char* proxyUsername,
return FALSE; return FALSE;
} }
status = recv_socks_reply(bufferedBio, buf, 2, "AUTH REQ", 1); status = recv_socks_reply(context, bufferedBio, buf, 2, "AUTH REQ", 1);
if (status < 2) if (status < 2)
return FALSE; return FALSE;
@ -824,7 +865,7 @@ static BOOL socks_proxy_connect(BIO* bufferedBio, const char* proxyUsername,
return FALSE; return FALSE;
} }
status = recv_socks_reply(bufferedBio, buf, sizeof(buf), "CONN REQ", 5); status = recv_socks_reply(context, bufferedBio, buf, sizeof(buf), "CONN REQ", 5);
if (status < 4) if (status < 4)
return FALSE; return FALSE;

View File

@ -26,7 +26,7 @@
BOOL proxy_prepare(rdpSettings* settings, const char** lpPeerHostname, UINT16* lpPeerPort, BOOL proxy_prepare(rdpSettings* settings, const char** lpPeerHostname, UINT16* lpPeerPort,
const char** lpProxyUsername, const char** lpProxyPassword); const char** lpProxyUsername, const char** lpProxyPassword);
BOOL proxy_connect(rdpSettings* settings, BIO* bio, const char* proxyUsername, BOOL proxy_connect(rdpContext* context, BIO* bio, const char* proxyUsername,
const char* proxyPassword, const char* hostname, UINT16 port); const char* proxyPassword, const char* hostname, UINT16 port);
#endif /* FREERDP_LIB_CORE_HTTP_PROXY_H */ #endif /* FREERDP_LIB_CORE_HTTP_PROXY_H */

View File

@ -595,8 +595,8 @@ BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 por
if (isProxyConnection) if (isProxyConnection)
{ {
if (!proxy_connect(settings, transport->frontBio, proxyUsername, proxyPassword, if (!proxy_connect(context, transport->frontBio, proxyUsername, proxyPassword, hostname,
hostname, port)) port))
return FALSE; return FALSE;
} }