proxy: rework proxy channel treatments for statefull drdynvc

The rework introduce a stateful dynamic channel treatment, so that we can take early decisions
for data packet (dropping all the current packet or pass it), but also reassemble important
packets like channel creation.
This commit is contained in:
David Fort
2022-03-07 13:46:49 +01:00
committed by akallabeth
parent f232562d8b
commit 63d0d3e4cf
13 changed files with 902 additions and 208 deletions

View File

@@ -36,6 +36,7 @@
#include <freerdp/streamdump.h>
#include <freerdp/channels/wtsvc.h>
#include <freerdp/channels/channels.h>
#include <freerdp/channels/drdynvc.h>
#include <freerdp/build-config.h>
#include <freerdp/channels/rdpdr.h>
@@ -44,12 +45,14 @@
#include <freerdp/server/proxy/proxy_log.h>
#include "pf_server.h"
#include "pf_channel.h"
#include <freerdp/server/proxy/proxy_config.h>
#include "pf_client.h"
#include <freerdp/server/proxy/proxy_context.h>
#include "pf_update.h"
#include "proxy_modules.h"
#include "pf_utils.h"
#include "channels/pf_channel_drdynvc.h"
#include "channels/pf_channel_rdpdr.h"
#define TAG PROXY_TAG("server")
@@ -194,7 +197,7 @@ static BOOL pf_server_setup_channels(freerdp_peer* peer)
const char* cname = accepted_channels[i];
UINT16 channelId = WTSChannelGetId(peer, cname);
PROXY_LOG_INFO(TAG, ps, "Accepted channel: %s", cname);
PROXY_LOG_INFO(TAG, ps, "Accepted channel: %s (%d)", cname, channelId);
channelContext = ChannelContext_new(ps, cname, channelId);
if (!channelContext)
{
@@ -202,6 +205,34 @@ static BOOL pf_server_setup_channels(freerdp_peer* peer)
return FALSE;
}
if (strcmp(cname, DRDYNVC_SVC_CHANNEL_NAME) == 0)
{
if (!pf_channel_setup_drdynvc(ps->pdata, channelContext))
{
PROXY_LOG_ERR(TAG, ps, "error while setting up dynamic channel");
ChannelContext_free(channelContext);
return FALSE;
}
}
else if (strcmp(cname, RDPDR_SVC_CHANNEL_NAME) == 0 && (channelContext->channelMode == PF_UTILS_CHANNEL_INTERCEPT))
{
if (!pf_channel_setup_rdpdr(ps, channelContext))
{
PROXY_LOG_ERR(TAG, ps, "error while setting up redirection channel");
ChannelContext_free(channelContext);
return FALSE;
}
}
else
{
if (!pf_channel_setup_generic(channelContext))
{
PROXY_LOG_ERR(TAG, ps, "error while setting up generic channel");
ChannelContext_free(channelContext);
return FALSE;
}
}
if (!HashTable_Insert(byId, &channelContext->channel_id, channelContext))
{
ChannelContext_free(channelContext);
@@ -273,18 +304,6 @@ static BOOL pf_server_post_connect(freerdp_peer* peer)
if (!pf_modules_run_hook(pdata->module, HOOK_TYPE_SERVER_POST_CONNECT, pdata, peer))
return FALSE;
switch (pf_utils_get_channel_mode(ps->pdata->config, RDPDR_SVC_CHANNEL_NAME))
{
case PF_UTILS_CHANNEL_INTERCEPT:
if (!pf_channel_rdpdr_server_new(ps))
return FALSE;
if (!pf_channel_rdpdr_server_announce(ps))
return FALSE;
break;
default:
break;
}
/* Start a proxy's client in it's own thread */
if (!(pdata->client_thread = CreateThread(NULL, 0, pf_client_start, pc, 0, NULL)))
{
@@ -349,22 +368,6 @@ static BOOL pf_server_adjust_monitor_layout(freerdp_peer* peer)
return TRUE;
}
static BOOL pf_server_receive_channel_intercept(proxyData* pdata, UINT16 channelId,
const char* channel_name, const BYTE* data,
size_t size, UINT32 flags, size_t totalSize)
{
WINPR_ASSERT(pdata);
WINPR_ASSERT(channel_name);
if (strcmp(channel_name, RDPDR_SVC_CHANNEL_NAME) == 0)
return pf_channel_rdpdr_server_handle(pdata->ps, channelId, channel_name, data, size, flags,
totalSize);
WLog_ERR(TAG, "[%s]: Channel %s [0x%04" PRIx16 "] intercept mode not implemented, aborting",
__FUNCTION__, channel_name, channelId);
return FALSE;
}
static BOOL pf_server_receive_channel_data_hook(freerdp_peer* peer, UINT16 channelId,
const BYTE* data, size_t size, UINT32 flags,
size_t totalSize)
@@ -374,7 +377,7 @@ static BOOL pf_server_receive_channel_data_hook(freerdp_peer* peer, UINT16 chann
proxyData* pdata;
const proxyConfig* config;
const pServerChannelContext* channel;
UINT32 channelId32 = channelId;
UINT64 channelId64 = channelId;
WINPR_ASSERT(peer);
@@ -395,40 +398,32 @@ static BOOL pf_server_receive_channel_data_hook(freerdp_peer* peer, UINT16 chann
if (!pc)
goto original_cb;
channel = HashTable_GetItemValue(ps->channelsById, &channelId32);
channel = HashTable_GetItemValue(ps->channelsById, &channelId64);
if (!channel)
{
PROXY_LOG_ERR(TAG, ps, "channel id=%d not registered here, dropping", channelId32);
PROXY_LOG_ERR(TAG, ps, "channel id=%d not registered here, dropping", channelId64);
return TRUE;
}
switch (channel->channelMode)
switch (channel->onFrontData(pdata, channel, data, size, flags, totalSize))
{
case PF_UTILS_CHANNEL_BLOCK:
return TRUE;
case PF_UTILS_CHANNEL_PASSTHROUGH:
{
proxyChannelDataEventInfo ev;
case PF_CHANNEL_RESULT_PASS: {
proxyChannelDataEventInfo ev;
ev.channel_id = channelId;
ev.channel_name = channel->channel_name;
ev.data = data;
ev.data_len = size;
ev.flags = flags;
ev.total_size = totalSize;
if (!pf_modules_run_filter(pdata->module, FILTER_TYPE_SERVER_PASSTHROUGH_CHANNEL_DATA,
pdata, &ev))
return TRUE; /* Silently ignore */
return IFCALLRESULT(TRUE, pc->sendChannelData, pc, &ev);
}
case PF_UTILS_CHANNEL_INTERCEPT:
return pf_server_receive_channel_intercept(pdata, channelId, channel->channel_name,
data, size, flags, totalSize);
default:
break;
ev.channel_id = channelId;
ev.channel_name = channel->channel_name;
ev.data = data;
ev.data_len = size;
ev.flags = flags;
ev.total_size = totalSize;
return IFCALLRESULT(TRUE, pc->sendChannelData, pc, &ev);
}
case PF_CHANNEL_RESULT_DROP:
return TRUE;
case PF_CHANNEL_RESULT_ERROR:
return FALSE;
}
original_cb:
WINPR_ASSERT(pdata->server_receive_channel_data_original);