SOCKS proxy support

This commit is contained in:
Jiri Sasek
2017-08-18 19:17:17 +02:00
committed by Jiri Sasek
parent c5572b087a
commit b1c1549ad1
5 changed files with 164 additions and 6 deletions

View File

@@ -1317,6 +1317,8 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
compatibility = freerdp_client_detect_command_line(argc - 1, &argv[1], &flags,
allowUnknown);
settings->ProxyHostname = NULL;
if (compatibility)
{
WLog_WARN(TAG, "Using deprecated command-line interface!");
@@ -1819,6 +1821,9 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
}
CommandLineSwitchCase(arg, "proxy")
{
/* initial value */
settings->ProxyType = PROXY_TYPE_HTTP;
if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
{
p = strstr(arg->Value, "://");
@@ -1831,9 +1836,13 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
{
settings->ProxyType = PROXY_TYPE_HTTP;
}
else if (!strcmp("socks", arg->Value))
{
settings->ProxyType = PROXY_TYPE_SOCKS;
}
else
{
WLog_ERR(TAG, "Only HTTP proxys supported by now");
WLog_ERR(TAG, "Only HTTP and SOCKS proxies supported by now");
return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
}
@@ -1854,7 +1863,6 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
settings->ProxyHostname = (char*) malloc(length + 1);
strncpy(settings->ProxyHostname, arg->Value, length);
settings->ProxyHostname[length] = '\0';
settings->ProxyType = PROXY_TYPE_HTTP;
}
}
else

View File

@@ -137,7 +137,7 @@ static COMMAND_LINE_ARGUMENT_A args[] =
{ "port", COMMAND_LINE_VALUE_REQUIRED, "<number>", NULL, NULL, -1, NULL, "Server port" },
{ "print-reconnect-cookie", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Print base64 reconnect cookie after connecting" },
{ "printer", COMMAND_LINE_VALUE_OPTIONAL, "<name>[,<driver>]", NULL, NULL, -1, NULL, "Redirect printer device" },
{ "proxy", COMMAND_LINE_VALUE_REQUIRED, "[<proto>://]<host>:<port>", NULL, NULL, -1, NULL, "Proxy (see also environment variable below)" },
{ "proxy", COMMAND_LINE_VALUE_REQUIRED, "[<proto>://]<host>:<port>", NULL, NULL, -1, NULL, "Proxy settings: override env.var (see also environment variable below).\n\tProtocol \"socks\" should be given explicitly where \"http[s]\" is default.\n\tNote: socks proxy is not supported by env. variable" },
{ "pth", COMMAND_LINE_VALUE_REQUIRED, "<password-hash>", NULL, NULL, -1, "pass-the-hash", "Pass the hash (restricted admin mode)" },
{ "pwidth", COMMAND_LINE_VALUE_REQUIRED, "<width>", NULL, NULL, -1, NULL, "Physical width of display (in millimeters)" },
{ "reconnect-cookie", COMMAND_LINE_VALUE_REQUIRED, "<base64-cookie>", NULL, NULL, -1, NULL, "Pass base64 reconnect cookie to the connection" },

View File

@@ -471,6 +471,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL;
#define PROXY_TYPE_NONE 0
#define PROXY_TYPE_HTTP 1
#define PROXY_TYPE_SOCKS 2
/* Settings */

View File

@@ -29,7 +29,8 @@
#define CRLF "\r\n"
#define TAG FREERDP_TAG("core.proxy")
BOOL http_proxy_connect(BIO* bufferedBio, const char* hostname, UINT16 port);
static BOOL http_proxy_connect(BIO* bufferedBio, const char* hostname, UINT16 port);
static BOOL socks_proxy_connect(BIO* bufferedBio, const char* hostname, UINT16 port);
void proxy_read_environment(rdpSettings* settings, char* envname);
BOOL proxy_prepare(rdpSettings* settings, const char** lpPeerHostname, UINT16* lpPeerPort,
@@ -160,13 +161,16 @@ BOOL proxy_connect(rdpSettings* settings, BIO* bufferedBio, const char* hostname
case PROXY_TYPE_HTTP:
return http_proxy_connect(bufferedBio, hostname, port);
case PROXY_TYPE_SOCKS:
return socks_proxy_connect(bufferedBio, hostname, port);
default:
WLog_ERR(TAG, "Invalid internal proxy configuration");
return FALSE;
}
}
BOOL http_proxy_connect(BIO* bufferedBio, const char* hostname, UINT16 port)
static BOOL http_proxy_connect(BIO* bufferedBio, const char* hostname, UINT16 port)
{
int status;
wStream* s;
@@ -255,3 +259,136 @@ BOOL http_proxy_connect(BIO* bufferedBio, const char* hostname, UINT16 port)
return TRUE;
}
/* SOCKS Proxy auth methods by rfc1928 */
#define AUTH_M_NO_AUTH 0
#define AUTH_M_GSSAPI 1
#define AUTH_M_USR_PASS 2
static BOOL socks_proxy_connect(BIO* bufferedBio, const char* hostname, UINT16 port)
{
int status;
BYTE buf[280], hostnlen = 0xff & strlen(hostname);
/* CONN REQ replies in enum. order */
static const char *rplstat[] = {
"succeeded",
"general SOCKS server failure",
"connection not allowed by ruleset",
"Network unreachable",
"Host unreachable",
"Connection refused",
"TTL expired",
"Command not supported",
"Address type not supported"
};
/* select auth. method */
memset(buf, '\0', sizeof(buf));
buf[0] = 5; /* SOCKS version */
buf[1] = 1; /* #of methods offered */
buf[2] = AUTH_M_NO_AUTH;
status = BIO_write(bufferedBio, buf, 3);
if (status != 3)
{
WLog_ERR(TAG, "SOCKS proxy: failed to write AUTH METHOD request");
return FALSE;
}
/* Read result SOCK reply */
memset(buf, '\0', sizeof(buf));
for(;;) {
status = BIO_read(bufferedBio, buf, sizeof(buf));
if (status > 0) break;
else if (status < 0)
{
/* Error? */
if (BIO_should_retry(bufferedBio))
{
USleep(100);
continue;
}
WLog_ERR(TAG, "Failed reading AUTH reply from SOCKS proxy (Status %d)", status);
return FALSE;
}
else if (status == 0)
{
/* Error? */
WLog_ERR(TAG, "Failed reading AUTH reply from SOCKS proxy (BIO_read returned zero)");
return FALSE;
}
}
if (buf[0] != 5)
{
WLog_ERR(TAG, "SOCKS Proxy version is not 5 (AUTH)");
return FALSE;
}
if (buf[1] != AUTH_M_NO_AUTH)
{
WLog_ERR(TAG, "SOCKS Proxy: (NO AUTH) method was not selected by proxy");
return FALSE;
}
/* CONN request */
memset(buf, '\0', sizeof(buf));
buf[0] = 5; /* SOCKS version */
buf[1] = 1; /* command = connect */
/* 3rd octet is reserved x00 */
buf[3] = 3; /* addr.type = FQDN */
buf[4] = hostnlen; /* DST.ADDR */
memcpy(buf +5, hostname, hostnlen);
/* follows DST.PORT in netw. format */
buf[hostnlen +5] = 0xff & (port >> 8);
buf[hostnlen +6] = 0xff & port;
status = BIO_write(bufferedBio, buf, hostnlen +7);
if (status != (hostnlen +7))
{
WLog_ERR(TAG, "SOCKS proxy: failed to write CONN REQ");
return FALSE;
}
/* Read result SOCK reply */
memset(buf, '\0', sizeof(buf));
for(;;) {
status = BIO_read(bufferedBio, buf, sizeof(buf));
if (status > 0) break;
else if (status < 0)
{
/* Error? */
if (BIO_should_retry(bufferedBio))
{
USleep(100);
continue;
}
WLog_ERR(TAG, "Failed reading reply from SOCKS proxy (Status %d)", status);
return FALSE;
}
else if (status == 0)
{
/* Error? */
WLog_ERR(TAG, "Failed reading reply from SOCKS proxy (BIO_read returned zero)");
return FALSE;
}
}
if (buf[0] != 5)
{
WLog_ERR(TAG, "SOCKS Proxy version is not 5 (CONN REQ)");
return FALSE;
}
if (buf[1] == 0)
{
WLog_INFO(TAG, "Successfully connected to %s:%d", hostname, port);
return TRUE;
}
if (buf[1] > 0 && buf[1] < 9)
WLog_INFO(TAG, "SOCKS Proxy replied: %s", rplstat[buf[1]]);
else
WLog_INFO(TAG, "SOCKS Proxy replied: %d status not listed in rfc1928", buf[1]);
return FALSE;
}

View File

@@ -52,6 +52,7 @@
#include "fastpath.h"
#include "transport.h"
#include "rdp.h"
#include "proxy.h"
#define TAG FREERDP_TAG("core.transport")
@@ -404,7 +405,14 @@ BOOL transport_connect(rdpTransport* transport, const char* hostname,
}
else
{
sockfd = freerdp_tcp_connect(context, settings, hostname, port, timeout);
UINT16 peerPort;
const char *peerHostname;
BOOL isProxyConnection = proxy_prepare(settings, &peerHostname, &peerPort, TRUE);
if (isProxyConnection)
sockfd = freerdp_tcp_connect(context, settings, peerHostname, peerPort, timeout);
else
sockfd = freerdp_tcp_connect(context, settings, hostname, port, timeout);
if (sockfd < 1)
return FALSE;
@@ -412,6 +420,10 @@ BOOL transport_connect(rdpTransport* transport, const char* hostname,
if (!transport_attach(transport, sockfd))
return FALSE;
if (isProxyConnection)
if (!proxy_connect(settings, transport->frontBio, hostname, port))
return FALSE;
status = TRUE;
}