mirror of
https://github.com/morgan9e/FreeRDP
synced 2026-04-15 00:44:19 +09:00
SOCKS proxy support
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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" },
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user