server: proxy: implement external routing

This commit is contained in:
Kobi Mizrachi 2020-09-08 14:03:56 +03:00 committed by akallabeth
parent c2c9abee5a
commit 67cfcb0af6
9 changed files with 86 additions and 31 deletions

View File

@ -9,8 +9,8 @@ Port = 3389
; and the /load-balance-info: CLI option for xfreerdp. Otherwise, the server
; will always connect to the same target, using the configured values of `Host`
; and `Port`.
UseLoadBalanceInfo = TRUE
Host = FakeHost
FixedTarget = TRUE
Host = CustomHost
Port = 3389
[Input]

View File

@ -66,6 +66,7 @@ static proxyPlugin demo_plugin = {
NULL, /* MouseEvent */
NULL, /* ClientChannelData */
NULL, /* ServerChannelData */
NULL /* ServerFetchTargetAddr */
};
BOOL proxy_module_entry_point(proxyPluginsManager* plugins_manager)

View File

@ -61,6 +61,7 @@ typedef struct proxy_plugin
proxyFilterFn MouseEvent;
proxyFilterFn ClientChannelData; /* passthrough channels data */
proxyFilterFn ServerChannelData; /* passthrough channels data */
proxyFilterFn ServerFetchTargetAddr;
} proxyPlugin;
/*
@ -111,6 +112,27 @@ typedef struct channel_data_event_info
const BYTE* data;
size_t data_len;
} proxyChannelDataEventInfo;
typedef enum proxy_fetch_target_method
{
PROXY_FETCH_TARGET_METHOD_DEFAULT,
PROXY_FETCH_TARGET_METHOD_CONFIG,
PROXY_FETCH_TARGET_METHOD_LOAD_BALANCE_INFO,
PROXY_FETCH_TARGET_USE_CUSTOM_ADDR
} ProxyFetchTargetMethod;
typedef struct fetch_target_event_info
{
/* out values */
char* target_address;
UINT16 target_port;
/*
* If this value is set to true by a plugin, target info will be fetched from config and proxy
* will connect any client to the same remote server.
*/
ProxyFetchTargetMethod fetch_method;
} proxyFetchTargetEventInfo;
#define WINPR_PACK_POP
#include <winpr/pack.h>

View File

@ -217,15 +217,8 @@ static BOOL pf_client_pre_connect(freerdp* instance)
*/
LOG_INFO(TAG, pc, "Loading addins");
if (!config->UseLoadBalanceInfo)
{
/* if target is static (i.e fetched from config). make sure to use peer's load-balance info,
* in order to support broker redirection.
*/
if (!pf_client_use_peer_load_balance_info(pc))
return FALSE;
}
if (!pf_client_use_peer_load_balance_info(pc))
return FALSE;
if (!pf_client_passthrough_channels_init(pc))
return FALSE;

View File

@ -157,7 +157,7 @@ static BOOL pf_config_load_target(wIniFile* ini, proxyConfig* config)
if (!config->TargetHost)
return FALSE;
config->UseLoadBalanceInfo = pf_config_get_bool(ini, "Target", "UseLoadBalanceInfo");
config->FixedTarget = pf_config_get_bool(ini, "Target", "FixedTarget");
return TRUE;
}
@ -307,7 +307,7 @@ void pf_server_config_print(proxyConfig* config)
CONFIG_PRINT_STR(config, Host);
CONFIG_PRINT_UINT16(config, Port);
if (!config->UseLoadBalanceInfo)
if (config->FixedTarget)
{
CONFIG_PRINT_SECTION("Target");
CONFIG_PRINT_STR(config, TargetHost);

View File

@ -34,7 +34,7 @@ struct proxy_config
UINT16 Port;
/* target */
BOOL UseLoadBalanceInfo;
BOOL FixedTarget;
char* TargetHost;
UINT16 TargetPort;

View File

@ -39,12 +39,8 @@ static wArrayList* handles_list = NULL; /* list of module handles to free at shu
typedef BOOL (*moduleEntryPoint)(proxyPluginsManager* plugins_manager);
static const char* FILTER_TYPE_STRINGS[] = {
"KEYBOARD_EVENT",
"MOUSE_EVENT",
"CLIENT_CHANNEL_DATA",
"SERVER_CHANNEL_DATA",
};
static const char* FILTER_TYPE_STRINGS[] = { "KEYBOARD_EVENT", "MOUSE_EVENT", "CLIENT_CHANNEL_DATA",
"SERVER_CHANNEL_DATA", "SERVER_FETCH_TARGET_ADDR" };
static const char* HOOK_TYPE_STRINGS[] = {
"CLIENT_PRE_CONNECT", "CLIENT_POST_CONNECT", "CLIENT_LOGIN_FAILURE", "CLIENT_END_PAINT",
@ -165,6 +161,11 @@ BOOL pf_modules_run_filter(PF_FILTER_TYPE type, proxyData* pdata, void* param)
case FILTER_TYPE_SERVER_PASSTHROUGH_CHANNEL_DATA:
IFCALLRET(plugin->ServerChannelData, result, pdata, param);
break;
case FILTER_TYPE_SERVER_FETCH_TARGET_ADDR:
IFCALLRET(plugin->ServerFetchTargetAddr, result, pdata, param);
break;
default:
WLog_ERR(TAG, "invalid filter called");
}

View File

@ -32,7 +32,9 @@ enum _PF_FILTER_TYPE
FILTER_TYPE_KEYBOARD,
FILTER_TYPE_MOUSE,
FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_DATA,
FILTER_TYPE_SERVER_PASSTHROUGH_CHANNEL_DATA,
FILTER_TYPE_SERVER_FETCH_TARGET_ADDR,
FILTER_LAST
};

View File

@ -100,22 +100,58 @@ static BOOL pf_server_get_target_info(rdpContext* context, rdpSettings* settings
proxyConfig* config)
{
pServerContext* ps = (pServerContext*)context;
proxyFetchTargetEventInfo ev = { 0 };
LOG_INFO(TAG, ps, "fetching target from %s",
config->UseLoadBalanceInfo ? "load-balance-info" : "config");
ev.fetch_method = config->FixedTarget ? PROXY_FETCH_TARGET_METHOD_CONFIG
: PROXY_FETCH_TARGET_METHOD_LOAD_BALANCE_INFO;
if (config->UseLoadBalanceInfo)
return pf_server_parse_target_from_routing_token(context, &settings->ServerHostname,
&settings->ServerPort);
/* use hardcoded target info from configuration */
if (!(settings->ServerHostname = _strdup(config->TargetHost)))
{
LOG_ERR(TAG, ps, "strdup failed!");
if (!pf_modules_run_filter(FILTER_TYPE_SERVER_FETCH_TARGET_ADDR, ps->pdata, &ev))
return FALSE;
switch (ev.fetch_method)
{
case PROXY_FETCH_TARGET_METHOD_DEFAULT:
case PROXY_FETCH_TARGET_METHOD_LOAD_BALANCE_INFO:
return pf_server_parse_target_from_routing_token(context, &settings->ServerHostname,
&settings->ServerPort);
case PROXY_FETCH_TARGET_METHOD_CONFIG:
{
settings->ServerPort = config->TargetPort > 0 ? 3389 : settings->ServerPort;
settings->ServerHostname = _strdup(config->TargetHost);
if (!settings->ServerHostname)
{
LOG_ERR(TAG, ps, "strdup failed!");
return FALSE;
}
return TRUE;
}
case PROXY_FETCH_TARGET_USE_CUSTOM_ADDR:
{
if (!ev.target_address)
{
WLog_ERR(TAG, "router: using CUSTOM_ADDR fetch method, but target_address == NULL");
return FALSE;
}
settings->ServerHostname = _strdup(ev.target_address);
if (!settings->ServerHostname)
{
LOG_ERR(TAG, ps, "strdup failed!");
return FALSE;
}
free(ev.target_address);
settings->ServerPort = ev.target_port;
return TRUE;
}
default:
WLog_WARN(TAG, "unknown target fetch method: %d", ev.fetch_method);
return FALSE;
}
settings->ServerPort = config->TargetPort > 0 ? 3389 : settings->ServerPort;
return TRUE;
}