Start support for HTTP Proxy. Does almost work; need to fully read and parse HTTP Proxy response.

This commit is contained in:
Chris 2014-03-21 18:58:28 +01:00
parent 14208dcb8d
commit 996f8ccb94
8 changed files with 215 additions and 1 deletions

View File

@ -504,6 +504,10 @@ if(ANDROID)
endif()
endif()
if(WITH_HTTP_PROXY)
add_definitions(-DWITH_HTTP_PROXY)
endif()
# Unit Tests
include(CTest)

View File

@ -72,6 +72,9 @@ COMMAND_LINE_ARGUMENT_A args[] =
{ "gu", COMMAND_LINE_VALUE_REQUIRED, "[<domain>\\]<user> or <user>[@<domain>]", NULL, NULL, -1, NULL, "Gateway username" },
{ "gp", COMMAND_LINE_VALUE_REQUIRED, "<password>", NULL, NULL, -1, NULL, "Gateway password" },
{ "gd", COMMAND_LINE_VALUE_REQUIRED, "<domain>", NULL, NULL, -1, NULL, "Gateway domain" },
#ifdef WITH_HTTP_PROXY
{ "http-proxy", COMMAND_LINE_VALUE_REQUIRED, "<host>:<port>", NULL, NULL, -1, NULL, "HTTP Proxy" },
#endif
{ "load-balance-info", COMMAND_LINE_VALUE_REQUIRED, "<info string>", NULL, NULL, -1, NULL, "Load balance info" },
{ "app", COMMAND_LINE_VALUE_REQUIRED, "<executable path> or <||alias>", NULL, NULL, -1, NULL, "Remote application program" },
{ "app-name", COMMAND_LINE_VALUE_REQUIRED, "<app name>", NULL, NULL, -1, NULL, "Remote application name for user interface" },
@ -1349,6 +1352,32 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
settings->GatewayUseSameCredentials = TRUE;
settings->GatewayEnabled = TRUE;
}
#ifdef WITH_HTTP_PROXY
CommandLineSwitchCase(arg, "http-proxy")
{
if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
{
/* TODO: parse "http://" URL? */
p = strchr(arg->Value, ':');
if (p)
{
length = (int) (p - arg->Value);
settings->HTTPProxyPort = atoi(&p[1]);
settings->HTTPProxyHostname = (char*) malloc(length + 1);
strncpy(settings->HTTPProxyHostname, arg->Value, length);
settings->HTTPProxyHostname[length] = '\0';
settings->HTTPProxyEnabled = TRUE;
}
else
{
/* TODO parse encironment variable here? */
fprintf(stderr, "Option http-proxy needs argument. Ignored.\n");
}
}
}
#endif
CommandLineSwitchCase(arg, "gu")
{
char* user;

View File

@ -68,6 +68,8 @@ option(STATIC_CHANNELS "Build channels statically" ON)
option(WITH_CHANNELS "Build virtual channel plugins" ON)
option(WITH_HTTP_PROXY "Build HTTP proxy support" OFF)
if(WITH_CLIENT AND WITH_CHANNELS)
option(WITH_CLIENT_CHANNELS "Build virtual channel plugins" ON)
endif()

View File

@ -669,6 +669,11 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL;
#define FreeRDP_GatewayCredentialsSource 1990
#define FreeRDP_GatewayUseSameCredentials 1991
#define FreeRDP_GatewayEnabled 1992
#ifdef WITH_HTTP_PROXY
#define FreeRDP_HTTPProxyEnabled 2995
#define FreeRDP_HTTPProxyHostname 2996
#define FreeRDP_HTTPProxyPort 2997
#endif
#define FreeRDP_RemoteApplicationMode 2112
#define FreeRDP_RemoteApplicationName 2113
#define FreeRDP_RemoteApplicationIcon 2114
@ -1076,6 +1081,13 @@ struct rdp_settings
UINT64 padding2048[2048 - 1993]; /* 1993 */
UINT64 padding2112[2112 - 2048]; /* 2048 */
#ifdef WITH_HTTP_PROXY
/* HTTP Proxy */
ALIGN64 BOOL HTTPProxyEnabled; /* 1995 */
ALIGN64 char* HTTPProxyHostname; /* 1996 */
ALIGN64 UINT32 HTTPProxyPort; /* 1997 */
#endif
/**
* RemoteApp
*/

View File

@ -746,6 +746,12 @@ BOOL freerdp_get_param_bool(rdpSettings* settings, int id)
return settings->GatewayEnabled;
break;
#ifdef WITH_HTTP_PROXY
case FreeRDP_HTTPProxyEnabled:
return settings->HTTPProxyEnabled;
break;
#endif
case FreeRDP_RemoteApplicationMode:
return settings->RemoteApplicationMode;
break;
@ -1218,6 +1224,12 @@ int freerdp_set_param_bool(rdpSettings* settings, int id, BOOL param)
settings->GatewayEnabled = param;
break;
#ifdef WITH_HTTP_PROXY
case FreeRDP_HTTPProxyEnabled:
settings->HTTPProxyEnabled = param;
break;
#endif
case FreeRDP_RemoteApplicationMode:
settings->RemoteApplicationMode = param;
break;
@ -1603,6 +1615,12 @@ UINT32 freerdp_get_param_uint32(rdpSettings* settings, int id)
return settings->GatewayCredentialsSource;
break;
#ifdef WITH_HTTP_PROXY
case FreeRDP_HTTPProxyPort:
return settings->HTTPProxyPort;
break;
#endif
case FreeRDP_RemoteAppNumIconCaches:
return settings->RemoteAppNumIconCaches;
break;
@ -1911,6 +1929,12 @@ int freerdp_set_param_uint32(rdpSettings* settings, int id, UINT32 param)
settings->GatewayCredentialsSource = param;
break;
#ifdef WITH_HTTP_PROXY
case FreeRDP_HTTPProxyPort:
settings->HTTPProxyPort = param;
break;
#endif
case FreeRDP_RemoteAppNumIconCaches:
settings->RemoteAppNumIconCaches = param;
break;
@ -2233,6 +2257,12 @@ char* freerdp_get_param_string(rdpSettings* settings, int id)
return settings->GatewayDomain;
break;
#ifdef WITH_HTTP_PROXY
case FreeRDP_HTTPProxyHostname:
return settings->HTTPProxyHostname;
break;
#endif
case FreeRDP_RemoteApplicationName:
return settings->RemoteApplicationName;
break;
@ -2437,6 +2467,13 @@ int freerdp_set_param_string(rdpSettings* settings, int id, const char* param)
settings->GatewayDomain = _strdup(param);
break;
#ifdef WITH_HTTP_PROXY
case FreeRDP_HTTPProxyHostname:
free(settings->HTTPProxyHostname);
settings->HTTPProxyHostname = _strdup(param);
break;
#endif
case FreeRDP_RemoteApplicationName:
free(settings->RemoteApplicationName);
settings->RemoteApplicationName = _strdup(param);

View File

@ -481,6 +481,9 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings)
_settings->GatewayUsername = _strdup(settings->GatewayUsername); /* 1987 */
_settings->GatewayPassword = _strdup(settings->GatewayPassword); /* 1988 */
_settings->GatewayDomain = _strdup(settings->GatewayDomain); /* 1989 */
#ifdef WITH_HTTP_PROXY
_settings->HTTPProxyHostname = settings->HTTPProxyHostname; /* 199x */
#endif
_settings->RemoteApplicationName = _strdup(settings->RemoteApplicationName); /* 2113 */
_settings->RemoteApplicationIcon = _strdup(settings->RemoteApplicationIcon); /* 2114 */
_settings->RemoteApplicationProgram = _strdup(settings->RemoteApplicationProgram); /* 2115 */
@ -534,6 +537,9 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings)
_settings->GatewayUsageMethod = settings->GatewayUsageMethod; /* 1984 */
_settings->GatewayPort = settings->GatewayPort; /* 1985 */
_settings->GatewayCredentialsSource = settings->GatewayCredentialsSource; /* 1990 */
#ifdef WITH_HTTP_PROXY
_settings->HTTPProxyPort = settings->HTTPProxyPort; /* 199x */
#endif
_settings->RemoteApplicationExpandCmdLine = settings->RemoteApplicationExpandCmdLine; /* 2119 */
_settings->RemoteApplicationExpandWorkingDir = settings->RemoteApplicationExpandWorkingDir; /* 2120 */
_settings->RemoteAppNumIconCaches = settings->RemoteAppNumIconCaches; /* 2122 */
@ -651,6 +657,9 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings)
_settings->PlayRemoteFx = settings->PlayRemoteFx; /* 1857 */
_settings->GatewayUseSameCredentials = settings->GatewayUseSameCredentials; /* 1991 */
_settings->GatewayEnabled = settings->GatewayEnabled; /* 1992 */
#ifdef WITH_HTTP_PROXY
_settings->HTTPProxyEnabled = settings->HTTPProxyEnabled; /* 1995 */
#endif
_settings->RemoteApplicationMode = settings->RemoteApplicationMode; /* 2112 */
_settings->DisableRemoteAppCapsCheck = settings->DisableRemoteAppCapsCheck; /* 2121 */
_settings->RemoteAppLanguageBarSupported = settings->RemoteAppLanguageBarSupported; /* 2124 */

View File

@ -327,6 +327,61 @@ BOOL transport_connect_nla(rdpTransport* transport)
return TRUE;
}
#ifdef WITH_HTTP_PROXY
/* TODO move into core/tcp.c? */
BOOL transport_http_proxy_connect(rdpTransport* transport, const char* hostname, UINT16 port)
{
int status;
wStream* s;
char str[32];
_itoa_s(port, str, sizeof(str), 10);
s = Stream_New(NULL, 200);
Stream_Write(s, "CONNECT ", 8);
Stream_Write(s, hostname, strlen(hostname));
Stream_Write_UINT8(s, ':');
Stream_Write(s, str, strlen(str));
Stream_Write(s, " HTTP/1.1\r\n\r\nHost: ", 19);
Stream_Write(s, hostname, strlen(hostname));
Stream_Write_UINT8(s, ':');
Stream_Write(s, str, strlen(str));
Stream_Write(s, "\r\n\r\n", 4);
// Send Host: header? (RFC2817)
//fprintf(stderr, "Sending CONNECT %.*s:%.*s\n", strlen(hostname), hostname, strlen(str), str);
fprintf(stderr, "Sending \"%.*s\"...\n", (int)Stream_GetPosition(s), Stream_Buffer(s));
status = transport_write(transport, s);
if (status < 0) {
fprintf(stderr, "Error writing: status=%d\n", status);
return status;
}
fprintf(stderr, "Sent!\n");
// Read result...
memset(str, 0, sizeof(str));
status = tcp_read(transport->TcpIn, (BYTE*)str, sizeof(str)-1);
if (status <= 0) {
// Error?
return FALSE;
}
fprintf(stderr, "Reply: \"%.*s\"\n", status, str);
// TODO read until "\r\n\r\n"
if (strstr(str, "200") == NULL) {
return FALSE;
}
return TRUE;
}
#endif
BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16 port)
{
rdpTsg* tsg = tsg_new(transport);
@ -374,6 +429,50 @@ BOOL transport_connect(rdpTransport* transport, const char* hostname, UINT16 por
transport->async = settings->AsyncTransport;
#ifdef WITH_HTTP_PROXY
if (transport->settings->HTTPProxyEnabled)
{
status = tcp_connect(transport->TcpIn, settings->HTTPProxyHostname, settings->HTTPProxyPort);
if (status) {
if (transport->settings->GatewayEnabled) {
transport->layer = TRANSPORT_LAYER_HTTP_PROXY_IN;
status = transport_http_proxy_connect(transport, settings->GatewayHostname, settings->GatewayPort);
if (status) {
// Connect second channel
transport->TcpOut = tcp_new(settings);
status = tcp_connect(transport->TcpOut, settings->HTTPProxyHostname, settings->HTTPProxyPort);
}
if (status) {
transport->layer = TRANSPORT_LAYER_HTTP_PROXY_OUT;
status = transport_http_proxy_connect(transport, settings->GatewayHostname, settings->GatewayPort);
}
if (status) {
transport->layer = TRANSPORT_LAYER_TSG;
transport->SplitInputOutput = TRUE;
status = transport_tsg_connect(transport, hostname, port);
}
}
else {
transport->layer = TRANSPORT_LAYER_TCP;
transport->SplitInputOutput = FALSE;
transport->TcpOut = transport->TcpIn;
status = tcp_connect(transport->TcpIn, settings->HTTPProxyHostname, settings->HTTPProxyPort);
if (status) {
status = transport_http_proxy_connect(transport, hostname, port);
}
}
}
}
else
#endif
if (transport->settings->GatewayEnabled)
{
transport->layer = TRANSPORT_LAYER_TSG;
@ -555,6 +654,12 @@ int transport_read_layer(rdpTransport* transport, BYTE* data, int bytes)
else if (transport->layer == TRANSPORT_LAYER_TSG_TLS) {
status = tls_read(transport->TsgTls, data + read, bytes - read);
}
#ifdef WITH_HTTP_PROXY
else if (transport->layer == TRANSPORT_LAYER_HTTP_PROXY_IN)
status = tcp_read(transport->TcpIn, data + read, bytes - read);
else if (transport->layer == TRANSPORT_LAYER_HTTP_PROXY_OUT)
status = tcp_read(transport->TcpOut, data + read, bytes - read);
#endif
/* blocking means that we can't continue until this is read */
@ -737,6 +842,12 @@ int transport_write(rdpTransport* transport, wStream* s)
status = tsg_write(transport->tsg, Stream_Pointer(s), length);
else if (transport->layer == TRANSPORT_LAYER_TSG_TLS)
status = tls_write(transport->TsgTls, Stream_Pointer(s), length);
#ifdef WITH_HTTP_PROXY
else if (transport->layer == TRANSPORT_LAYER_HTTP_PROXY_IN)
status = tcp_write(transport->TcpIn, Stream_Pointer(s), length);
else if (transport->layer == TRANSPORT_LAYER_HTTP_PROXY_OUT)
status = tcp_write(transport->TcpOut, Stream_Pointer(s), length);
#endif
if (status < 0)
break; /* error occurred */
@ -757,6 +868,12 @@ int transport_write(rdpTransport* transport, wStream* s)
tcp_wait_write(transport->TcpOut);
else if (transport->layer == TRANSPORT_LAYER_TSG_TLS)
tls_wait_write(transport->TsgTls);
#ifdef WITH_HTTP_PROXY
else if (transport->layer == TRANSPORT_LAYER_HTTP_PROXY_IN)
tcp_wait_write(transport->TcpIn);
else if (transport->layer == TRANSPORT_LAYER_HTTP_PROXY_OUT)
tcp_wait_write(transport->TcpOut);
#endif
else
USleep(transport->SleepInterval);
}

View File

@ -26,7 +26,11 @@ typedef enum
TRANSPORT_LAYER_TLS,
TRANSPORT_LAYER_TSG,
TRANSPORT_LAYER_TSG_TLS,
TRANSPORT_LAYER_CLOSED
TRANSPORT_LAYER_CLOSED,
#ifdef WITH_HTTP_PROXY
TRANSPORT_LAYER_HTTP_PROXY_IN,
TRANSPORT_LAYER_HTTP_PROXY_OUT,
#endif
} TRANSPORT_LAYER;
typedef struct rdp_transport rdpTransport;