More abstracted proxy handling
authorChristian Plattner <ccpp@gmx.at>
Sat, 10 Dec 2016 22:13:35 +0000 (23:13 +0100)
committerChristian Plattner <ccpp@gmx.at>
Sat, 10 Dec 2016 22:13:35 +0000 (23:13 +0100)
client/common/cmdline.c
include/freerdp/settings.h
libfreerdp/common/settings.c
libfreerdp/core/gateway/rdg.c
libfreerdp/core/gateway/rpc.c
libfreerdp/core/proxy.c
libfreerdp/core/proxy.h
libfreerdp/core/settings.c
libfreerdp/core/transport.c

index d5eb5e4..de31e8e 100644 (file)
@@ -23,6 +23,7 @@
 #include "config.h"
 #endif
 
+#include <ctype.h>
 #include <assert.h>
 
 #include <winpr/crt.h>
@@ -82,7 +83,7 @@ static COMMAND_LINE_ARGUMENT_A args[] =
        { "gd", COMMAND_LINE_VALUE_REQUIRED, "<domain>", NULL, NULL, -1, NULL, "Gateway domain" },
        { "gt", COMMAND_LINE_VALUE_REQUIRED, "<rpc|http|auto>", NULL, NULL, -1, NULL, "Gateway transport type" },
        { "gateway-usage-method", COMMAND_LINE_VALUE_REQUIRED, "<direct|detect>", NULL, NULL, -1, "gum", "Gateway usage method" },
-       { "http-proxy", COMMAND_LINE_VALUE_REQUIRED, "<host>:<port>", NULL, NULL, -1, NULL, "HTTP Proxy" },
+       { "proxy", COMMAND_LINE_VALUE_REQUIRED, "[<protocol>://]<host>:<port>", NULL, NULL, -1, NULL, "Proxy (see also environment variable below)" },
        { "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" },
@@ -1787,28 +1788,44 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
                        settings->GatewayUseSameCredentials = TRUE;
                        freerdp_set_gateway_usage_method(settings, TSC_PROXY_MODE_DIRECT);
                }
-               CommandLineSwitchCase(arg, "http-proxy")
+               CommandLineSwitchCase(arg, "proxy")
                {
                        if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
                        {
+                               p = strstr(arg->Value, "://");
+                               if (p) {
+                                       *p = '\0';
+                                       if (!strcmp("http", arg->Value)) {
+                                               settings->ProxyType = PROXY_TYPE_HTTP;
+                                       } else {
+                                               WLog_ERR(TAG, "Only HTTP proxys supported by now");
+                                               return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
+                                       }
+                                       arg->Value = p + 3;
+                               }
+
                                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");
+                                       if (!isdigit(p[1])) {
+                                               WLog_ERR(TAG, "Could not parse proxy port");
+                                               return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
+                                       }
+                                       settings->ProxyPort = atoi(&p[1]);
+                                       settings->ProxyHostname = (char*) malloc(length + 1);
+                                       strncpy(settings->ProxyHostname, arg->Value, length);
+                                       settings->ProxyHostname[length] = '\0';
+
+                                       settings->ProxyType = PROXY_TYPE_HTTP;
                                }
                        }
+                       else
+                       {
+                               WLog_ERR(TAG, "Option http-proxy needs argument.");
+                               return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
+                       }
                }
                CommandLineSwitchCase(arg, "gu")
                {
index ff1dceb..0e3d13c 100644 (file)
@@ -470,6 +470,9 @@ struct _RDPDR_PARALLEL
 };
 typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL;
 
+#define PROXY_TYPE_NONE                0
+#define PROXY_TYPE_HTTP                1
+
 /* Settings */
 
 #ifdef __GNUC__
@@ -686,9 +689,9 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL;
 #define FreeRDP_GatewayRpcTransport                            1994
 #define FreeRDP_GatewayHttpTransport                           1995
 #define FreeRDP_GatewayUdpTransport                            1996
-#define FreeRDP_HTTPProxyEnabled                               2015
-#define FreeRDP_HTTPProxyHostname                              2016
-#define FreeRDP_HTTPProxyPort                                  2017
+#define FreeRDP_ProxyType                                      2015
+#define FreeRDP_ProxyHostname                                  2016
+#define FreeRDP_ProxyPort                                      2017
 #define FreeRDP_RemoteApplicationMode                          2112
 #define FreeRDP_RemoteApplicationName                          2113
 #define FreeRDP_RemoteApplicationIcon                          2114
@@ -1145,13 +1148,13 @@ struct rdp_settings
        ALIGN64 BOOL GatewayRpcTransport; /* 1994 */
        ALIGN64 BOOL GatewayHttpTransport; /* 1995 */
        ALIGN64 BOOL GatewayUdpTransport; /* 1996 */
-       UINT64 padding2048[2048 - 1997]; /* 1997 */
-       UINT64 padding2112[2112 - 2048]; /* 2048 */
+       UINT64 padding2048[2015 - 1997]; /* 1997 */
 
-       /* HTTP Proxy */
-       ALIGN64 BOOL HTTPProxyEnabled;  /* 1995 */
-       ALIGN64 char* HTTPProxyHostname;        /* 1996 */
-       ALIGN64 UINT32 HTTPProxyPort;   /* 1997 */
+       /* Proxy */
+       ALIGN64 UINT32 ProxyType;       /* 2015 */
+       ALIGN64 char* ProxyHostname;    /* 2016 */
+       ALIGN64 UINT16 ProxyPort;       /* 2017 */
+       UINT64 padding2112[2112 - 2018]; /* 2018 */
 
        /**
         * RemoteApp
index 6d3c839..dc5e5a1 100644 (file)
@@ -990,9 +990,6 @@ BOOL freerdp_get_param_bool(rdpSettings* settings, int id)
                case FreeRDP_GatewayUdpTransport:
                        return settings->GatewayUdpTransport;
 
-               case FreeRDP_HTTPProxyEnabled:
-                       return settings->HTTPProxyEnabled;
-
                case FreeRDP_RemoteApplicationMode:
                        return settings->RemoteApplicationMode;
 
@@ -1476,10 +1473,6 @@ int freerdp_set_param_bool(rdpSettings* settings, int id, BOOL param)
                        settings->GatewayUdpTransport = param;
                        break;
 
-               case FreeRDP_HTTPProxyEnabled:
-                       settings->HTTPProxyEnabled = param;
-                       break;
-
                case FreeRDP_RemoteApplicationMode:
                        settings->RemoteApplicationMode = param;
                        break;
@@ -1857,6 +1850,12 @@ UINT32 freerdp_get_param_uint32(rdpSettings* settings, int id)
                case FreeRDP_GatewayCredentialsSource:
                        return settings->GatewayCredentialsSource;
 
+               case FreeRDP_ProxyType:
+                       return settings->ProxyType;
+
+               case FreeRDP_ProxyPort:
+                       return settings->ProxyPort;
+
                case FreeRDP_RemoteAppNumIconCaches:
                        return settings->RemoteAppNumIconCaches;
 
@@ -2151,6 +2150,14 @@ int freerdp_set_param_uint32(rdpSettings* settings, int id, UINT32 param)
                        settings->GatewayCredentialsSource = param;
                        break;
 
+               case FreeRDP_ProxyType:
+                       settings->ProxyType = param;
+                       break;
+
+               case FreeRDP_ProxyPort:
+                       settings->ProxyPort = param;
+                       break;
+
                case FreeRDP_RemoteAppNumIconCaches:
                        settings->RemoteAppNumIconCaches = param;
                        break;
@@ -2480,6 +2487,9 @@ char* freerdp_get_param_string(rdpSettings* settings, int id)
                case FreeRDP_GatewayDomain:
                        return settings->GatewayDomain;
 
+               case FreeRDP_ProxyHostname:
+                       return settings->ProxyHostname;
+
                case FreeRDP_RemoteApplicationName:
                        return settings->RemoteApplicationName;
 
@@ -2687,8 +2697,8 @@ int freerdp_set_param_string(rdpSettings* settings, int id, const char* param)
                        tmp = &settings->GatewayDomain;
                        break;
 
-               case FreeRDP_HTTPProxyHostname:
-                       tmp = &settings->HTTPProxyHostname;
+               case FreeRDP_ProxyHostname:
+                       tmp = &settings->ProxyHostname;
                        break;
 
                case FreeRDP_RemoteApplicationName:
index 70fd83f..bf37982 100644 (file)
@@ -902,17 +902,11 @@ BOOL rdg_tls_out_connect(rdpRdg* rdg, const char* hostname, UINT16 port, int tim
        BIO* bufferedBio = NULL;
        rdpSettings* settings = rdg->settings;
        const char *peerHostname = settings->GatewayHostname;
-       int peerPort = settings->GatewayPort;
-       BOOL isProxyConnection = FALSE;
+       UINT16 peerPort = settings->GatewayPort;
+       BOOL isProxyConnection = proxy_prepare(settings, &peerHostname, &peerPort, TRUE);
 
        assert(hostname != NULL);
 
-       if (settings->HTTPProxyEnabled) {
-               peerHostname = settings->HTTPProxyHostname;
-               peerPort = settings->HTTPProxyPort;
-               isProxyConnection = TRUE;
-       }
-
        sockfd = freerdp_tcp_connect(rdg->context, settings, peerHostname,
                                        peerPort, timeout);
 
@@ -942,8 +936,8 @@ BOOL rdg_tls_out_connect(rdpRdg* rdg, const char* hostname, UINT16 port, int tim
        status = BIO_set_nonblock(bufferedBio, TRUE);
 
        if (isProxyConnection) {
-               if (!http_proxy_connect(bufferedBio, settings->GatewayHostname, settings->GatewayPort))
-                       return -1;
+               if (!proxy_connect(settings, bufferedBio, settings->GatewayHostname, settings->GatewayPort))
+                       return FALSE;
        }
 
        if (!status)
@@ -978,9 +972,9 @@ BOOL rdg_tls_in_connect(rdpRdg* rdg, const char* hostname, UINT16 port, int time
 
        assert(hostname != NULL);
 
-       if (settings->HTTPProxyEnabled) {
-               peerHostname = settings->HTTPProxyHostname;
-               peerPort = settings->HTTPProxyPort;
+       if (settings->ProxyType) {
+               peerHostname = settings->ProxyHostname;
+               peerPort = settings->ProxyPort;
                isProxyConnection = TRUE;
        }
 
index 0c8d6e8..fb87517 100644 (file)
@@ -760,14 +760,8 @@ int rpc_channel_tls_connect(RpcChannel* channel, int timeout)
        rdpContext* context = rpc->context;
        rdpSettings* settings = context->settings;
        const char *peerHostname = settings->GatewayHostname;
-       int peerPort = settings->GatewayPort;
-       BOOL isProxyConnection = FALSE;
-
-       if (settings->HTTPProxyEnabled) {
-               peerHostname = settings->HTTPProxyHostname;
-               peerPort = settings->HTTPProxyPort;
-               isProxyConnection = TRUE;
-       }
+       UINT16 peerPort = settings->GatewayPort;
+       BOOL isProxyConnection = proxy_prepare(settings, &peerHostname, &peerPort, TRUE);
 
        sockfd = freerdp_tcp_connect(context, settings, peerHostname,
                                        peerPort, timeout);
@@ -793,7 +787,7 @@ int rpc_channel_tls_connect(RpcChannel* channel, int timeout)
                return -1;
 
        if (isProxyConnection) {
-               if (!http_proxy_connect(bufferedBio, settings->GatewayHostname, settings->GatewayPort))
+               if (!proxy_connect(settings, bufferedBio, settings->GatewayHostname, settings->GatewayPort))
                        return -1;
        }
 
index cd724b5..2becda4 100644 (file)
@@ -17,6 +17,7 @@
  * limitations under the License.
  */
 
+#include <ctype.h>
 
 #include "proxy.h"
 #include "freerdp/settings.h"
 #define CRLF "\r\n"
 #define TAG FREERDP_TAG("core.proxy")
 
-void http_proxy_read_environment(rdpSettings *settings, char *envname)
+BOOL http_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, BOOL isHTTPS)
+{
+       /* For TSGateway, find the system HTTPS proxy automatically */
+       if (!settings->ProxyType)
+               proxy_read_environment(settings, "https_proxy");
+
+       if (!settings->ProxyType)
+               proxy_read_environment(settings, "HTTPS_PROXY");
+
+       if (settings->ProxyType) {
+               *lpPeerHostname = settings->ProxyHostname;
+               *lpPeerPort = settings->ProxyPort;
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+void proxy_read_environment(rdpSettings *settings, char *envname)
 {
        char env[256];
        DWORD envlen;
-       char *hostname, *pport;
 
-       envlen = GetEnvironmentVariableA(envname, env, sizeof(env));
+       envlen = GetEnvironmentVariableA(envname, env, sizeof(env)-1);
        if(!envlen)
                return;
 
-       if (strncmp(env, "http://", 7)) {
-               WLog_ERR(TAG, "Proxy url must have scheme http. Ignoring.");
-               return;
-       }
+       env[envlen] = '\0';
 
-       settings->HTTPProxyEnabled = TRUE;
+       proxy_parse_uri(settings, env);
+}
 
-       hostname = env + 7;
+BOOL proxy_parse_uri(rdpSettings *settings, const char *uri)
+{
+       const char *hostname, *pport;
+       const char *protocol;
+       const char *p;
+       int hostnamelen;
+
+       p = strstr(uri, "://");
+       if (p) {
+               protocol = uri;
+               if (p == uri+4 && !strncmp("http", uri, 4)) {
+                       settings->ProxyType = PROXY_TYPE_HTTP;
+               } else {
+                       WLog_ERR(TAG, "Only HTTP proxys supported by now");
+                       return FALSE;
+               }
+               uri = p + 3;
+       } else {
+               WLog_ERR(TAG, "No scheme in proxy URI");
+               return FALSE;
+       }
+
+       hostname = uri;
        pport = strchr(hostname, ':');
        if (pport) {
-               *pport = '\0';
-               settings->HTTPProxyPort = atoi(pport+1);
+               if (!isdigit(*(pport+1))) {
+                       WLog_ERR(TAG, "Could not parse proxy port");
+                       return FALSE;
+               }
+               settings->ProxyPort = atoi(pport+1);
        }
        else {
                /* The default is 80. Also for Proxys. */
-               settings->HTTPProxyPort = 80;
+               settings->ProxyPort = 80;
 
                pport = strchr(hostname, '/');
-               if(pport)
-                       *pport = '\0';
        }
 
-       freerdp_set_param_string(settings, FreeRDP_HTTPProxyHostname, hostname);
-       WLog_INFO(TAG, "Parsed proxy configuration: %s:%d", settings->HTTPProxyHostname, settings->HTTPProxyPort);
+       if(pport) {
+               hostnamelen = pport - hostname;
+       } else {
+               hostnamelen = strlen(hostname);
+       }
+
+       settings->ProxyHostname = strndup(hostname, hostnamelen);
+       WLog_INFO(TAG, "Parsed proxy configuration: %s://%s:%d", protocol, settings->ProxyHostname, settings->ProxyPort);
+       return TRUE;
+}
+
+BOOL proxy_connect(rdpSettings *settings, BIO *bufferedBio, const char *hostname, UINT16 port)
+{
+       switch (settings->ProxyType) {
+       case PROXY_TYPE_NONE:
+               return TRUE;
+       case PROXY_TYPE_HTTP:
+               return http_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)
index f868bbc..f29c562 100644 (file)
@@ -23,7 +23,8 @@
 #include "freerdp/settings.h"
 #include <openssl/bio.h>
 
-void http_proxy_read_environment(rdpSettings *settings, char *envname);
-BOOL http_proxy_connect(BIO *bio, const char* hostname, UINT16 port);
+BOOL proxy_prepare(rdpSettings *settings, const char **lpPeerHostname, UINT16 *lpPeerPort, BOOL isHTTPS);
+BOOL proxy_parse_uri(rdpSettings *settings, const char *uri);
+BOOL proxy_connect(rdpSettings *settings, BIO *bio, const char* hostname, UINT16 port);
 
 #endif
index 5e6f88e..e418dad 100644 (file)
@@ -670,7 +670,7 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings)
                CHECKED_STRDUP(GatewayUsername); /* 1987 */
                CHECKED_STRDUP(GatewayPassword); /* 1988 */
                CHECKED_STRDUP(GatewayDomain); /* 1989 */
-               CHECKED_STRDUP(HTTPProxyHostname); /* 2016 */
+               CHECKED_STRDUP(ProxyHostname); /* 2016 */
                CHECKED_STRDUP(RemoteApplicationName); /* 2113 */
                CHECKED_STRDUP(RemoteApplicationIcon); /* 2114 */
                CHECKED_STRDUP(RemoteApplicationProgram); /* 2115 */
index 45504d4..039bbeb 100644 (file)
@@ -51,7 +51,6 @@
 #include "fastpath.h"
 #include "transport.h"
 #include "rdp.h"
-#include "proxy.h"
 
 #define TAG FREERDP_TAG("core.transport")
 
@@ -225,13 +224,6 @@ BOOL transport_connect(rdpTransport* transport, const char* hostname,
 
        if (transport->GatewayEnabled)
        {
-               /* For TSGateway, find the system HTTPS proxy automatically */
-               if (!transport->settings->HTTPProxyEnabled)
-                       http_proxy_read_environment(settings, "https_proxy");
-
-               if (!transport->settings->HTTPProxyEnabled)
-                       http_proxy_read_environment(settings, "HTTPS_PROXY");
-
                if (!status && settings->GatewayHttpTransport)
                {
                        transport->rdg = rdg_new(transport);