32 #include <freerdp/server/proxy/proxy_modules_api.h>
33 #include <freerdp/server/proxy/proxy_context.h>
35 #include <freerdp/channels/drdynvc.h>
36 #include <freerdp/channels/rdpgfx.h>
37 #include <freerdp/utils/gfx.h>
39 #define TAG MODULE_TAG("persist-bitmap-filter")
41 static constexpr
char plugin_name[] =
"bitmap-filter";
42 static constexpr
char plugin_desc[] =
43 "this plugin deactivates and filters persistent bitmap cache.";
45 static const std::vector<std::string>& plugin_static_intercept()
47 static std::vector<std::string> vec;
49 vec.emplace_back(DRDYNVC_SVC_CHANNEL_NAME);
53 static const std::vector<std::string>& plugin_dyn_intercept()
55 static std::vector<std::string> vec;
57 vec.emplace_back(RDPGFX_DVC_CHANNEL_NAME);
65 [[nodiscard]]
bool skip()
const
70 [[nodiscard]]
bool skip(
size_t s)
79 [[nodiscard]]
size_t remaining()
const
84 [[nodiscard]]
size_t total()
const
86 return _totalSkipSize;
89 void setSkipSize(
size_t len)
91 _toSkip = _totalSkipSize = len;
94 [[nodiscard]]
bool drop()
const
104 [[nodiscard]] uint32_t channelId()
const
109 void setChannelId(uint32_t
id)
116 size_t _totalSkipSize = 0;
118 uint32_t _channelId = 0;
121 static BOOL filter_client_pre_connect(proxyPlugin* plugin, proxyData* pdata,
void* custom)
123 WINPR_ASSERT(plugin);
125 WINPR_ASSERT(pdata->pc);
126 WINPR_ASSERT(custom);
128 auto settings = pdata->pc->context.settings;
134 static BOOL filter_dyn_channel_intercept_list(proxyPlugin* plugin, proxyData* pdata,
void* arg)
138 WINPR_ASSERT(plugin);
142 auto intercept = std::find(plugin_dyn_intercept().begin(), plugin_dyn_intercept().end(),
143 data->name) != plugin_dyn_intercept().end();
145 data->intercept = TRUE;
149 static BOOL filter_static_channel_intercept_list(proxyPlugin* plugin, proxyData* pdata,
void* arg)
153 WINPR_ASSERT(plugin);
157 auto intercept = std::find(plugin_static_intercept().begin(), plugin_static_intercept().end(),
158 data->name) != plugin_static_intercept().end();
160 data->intercept = TRUE;
164 static size_t drdynvc_cblen_to_bytes(UINT8 cbLen)
179 static UINT32 drdynvc_read_variable_uint(
wStream* s, UINT8 cbLen)
186 Stream_Read_UINT8(s, val);
190 Stream_Read_UINT16(s, val);
194 Stream_Read_UINT32(s, val);
201 static BOOL drdynvc_try_read_header(
wStream* s, uint32_t& channelId,
size_t& length)
204 Stream_SetPosition(s, 0);
205 if (Stream_GetRemainingLength(s) < 1)
207 Stream_Read_UINT8(s, value);
209 const UINT8 cmd = (value & 0xf0) >> 4;
210 const UINT8 Sp = (value & 0x0c) >> 2;
211 const UINT8 cbChId = (value & 0x03);
222 const size_t channelIdLen = drdynvc_cblen_to_bytes(cbChId);
223 if (Stream_GetRemainingLength(s) < channelIdLen)
226 channelId = drdynvc_read_variable_uint(s, cbChId);
227 length = Stream_Length(s);
228 if (cmd == DATA_FIRST_PDU)
230 const size_t dataLen = drdynvc_cblen_to_bytes(Sp);
231 if (Stream_GetRemainingLength(s) < dataLen)
234 length = drdynvc_read_variable_uint(s, Sp);
240 static DynChannelState* filter_get_plugin_data(proxyPlugin* plugin, proxyData* pdata)
242 WINPR_ASSERT(plugin);
245 auto mgr =
static_cast<proxyPluginsManager*
>(plugin->custom);
248 WINPR_ASSERT(mgr->GetPluginData);
249 return static_cast<DynChannelState*
>(mgr->GetPluginData(mgr, plugin_name, pdata));
252 static BOOL filter_set_plugin_data(proxyPlugin* plugin, proxyData* pdata, DynChannelState* data)
254 WINPR_ASSERT(plugin);
257 auto mgr =
static_cast<proxyPluginsManager*
>(plugin->custom);
260 WINPR_ASSERT(mgr->SetPluginData);
261 return mgr->SetPluginData(mgr, plugin_name, pdata, data);
264 static UINT8 drdynvc_value_to_cblen(UINT32 value)
273 static BOOL drdynvc_write_variable_uint(
wStream* s, UINT32 value, UINT8 cbLen)
278 Stream_Write_UINT8(s,
static_cast<UINT8
>(value));
282 Stream_Write_UINT16(s,
static_cast<UINT16
>(value));
286 Stream_Write_UINT32(s, value);
293 static BOOL drdynvc_write_header(
wStream* s, UINT32 channelId)
295 const UINT8 cbChId = drdynvc_value_to_cblen(channelId);
296 const UINT8 value = (DATA_PDU << 4) | cbChId;
297 const size_t len = drdynvc_cblen_to_bytes(cbChId) + 1;
299 if (!Stream_EnsureRemainingCapacity(s, len))
302 Stream_Write_UINT8(s, value);
303 return drdynvc_write_variable_uint(s, value, cbChId);
307 size_t startPosition, UINT32 channelId)
311 Stream_SetPosition(data->data, startPosition);
312 if (!drdynvc_write_header(data->data, channelId))
315 if (!Stream_EnsureRemainingCapacity(data->data,
sizeof(UINT16)))
317 Stream_Write_UINT16(data->data, 0);
318 Stream_SealLength(data->data);
320 WLog_INFO(TAG,
"[SessionID=%s][%s] forwarding empty %s", sessionID, plugin_name,
321 rdpgfx_get_cmd_id_string(RDPGFX_CMDID_CACHEIMPORTOFFER));
322 data->rewritten = TRUE;
326 static BOOL filter_dyn_channel_intercept(proxyPlugin* plugin, proxyData* pdata,
void* arg)
330 WINPR_ASSERT(plugin);
334 data->result = PF_CHANNEL_RESULT_PASS;
335 if (!data->isBackData &&
336 (strncmp(data->name, RDPGFX_DVC_CHANNEL_NAME, ARRAYSIZE(RDPGFX_DVC_CHANNEL_NAME)) == 0))
338 auto state = filter_get_plugin_data(plugin, pdata);
341 WLog_ERR(TAG,
"[SessionID=%s][%s] missing custom data, aborting!", pdata->session_id,
345 const size_t inputDataLength = Stream_Length(data->data);
346 UINT16 cmdId = RDPGFX_CMDID_UNUSED_0000;
348 const auto pos = Stream_GetPosition(data->data);
353 uint32_t channelId = 0;
355 if (drdynvc_try_read_header(data->data, channelId, length))
357 if (Stream_GetRemainingLength(data->data) >= 2)
359 Stream_Read_UINT16(data->data, cmdId);
360 state->setSkipSize(length);
361 state->setDrop(
false);
367 case RDPGFX_CMDID_CACHEIMPORTOFFER:
368 state->setDrop(
true);
369 state->setChannelId(channelId);
374 Stream_SetPosition(data->data, pos);
380 if (!state->skip(inputDataLength))
386 "[SessionID=%s][%s] dropping %s packet [total:%" PRIuz
", current:%" PRIuz
387 ", remaining: %" PRIuz
"]",
388 pdata->session_id, plugin_name,
389 rdpgfx_get_cmd_id_string(RDPGFX_CMDID_CACHEIMPORTOFFER), state->total(),
390 inputDataLength, state->remaining());
391 data->result = PF_CHANNEL_RESULT_DROP;
394 if (state->remaining() == 0)
396 if (!filter_forward_empty_offer(pdata->session_id, data, pos,
408 static BOOL filter_server_session_started(proxyPlugin* plugin, proxyData* pdata,
void* )
410 WINPR_ASSERT(plugin);
413 auto state = filter_get_plugin_data(plugin, pdata);
416 auto newstate =
new DynChannelState();
417 if (!filter_set_plugin_data(plugin, pdata, newstate))
426 static BOOL filter_server_session_end(proxyPlugin* plugin, proxyData* pdata,
void* )
428 WINPR_ASSERT(plugin);
431 auto state = filter_get_plugin_data(plugin, pdata);
433 filter_set_plugin_data(plugin, pdata,
nullptr);
441 FREERDP_API BOOL proxy_module_entry_point(proxyPluginsManager* plugins_manager,
void* userdata);
446 BOOL proxy_module_entry_point(proxyPluginsManager* plugins_manager,
void* userdata)
448 proxyPlugin plugin = {};
450 plugin.name = plugin_name;
451 plugin.description = plugin_desc;
453 plugin.ServerSessionStarted = filter_server_session_started;
454 plugin.ServerSessionEnd = filter_server_session_end;
456 plugin.ClientPreConnect = filter_client_pre_connect;
458 plugin.StaticChannelToIntercept = filter_static_channel_intercept_list;
459 plugin.DynChannelToIntercept = filter_dyn_channel_intercept_list;
460 plugin.DynChannelIntercept = filter_dyn_channel_intercept;
462 plugin.custom = plugins_manager;
465 plugin.userdata = userdata;
467 return plugins_manager->RegisterPlugin(plugins_manager, &plugin);
FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL param)
Sets a BOOL settings value.