FreeRDP
Loading...
Searching...
No Matches
pf_channel.c
1
18#include <winpr/assert.h>
19#include <winpr/cast.h>
20
21#include <freerdp/freerdp.h>
22#include <freerdp/server/proxy/proxy_log.h>
23
24#include "proxy_modules.h"
25#include "pf_channel.h"
26#include "pf_client.h"
27#include "pf_server.h"
28
29#define TAG PROXY_TAG("channel")
30
32struct sChannelStateTracker
33{
34 pServerStaticChannelContext* channel;
35 ChannelTrackerMode mode;
36 wStream* currentPacket;
37 size_t currentPacketReceived;
38 size_t currentPacketSize;
39 size_t currentPacketFragments;
40
41 ChannelTrackerPeekFn peekFn;
42 void* trackerData;
43 proxyData* pdata;
44};
45
46WINPR_ATTR_NODISCARD
47static BOOL channelTracker_resetCurrentPacket(ChannelStateTracker* tracker)
48{
49 WINPR_ASSERT(tracker);
50
51 BOOL create = TRUE;
52 if (tracker->currentPacket)
53 {
54 const size_t cap = Stream_Capacity(tracker->currentPacket);
55 if (cap < 1ULL * 1000ULL * 1000ULL)
56 create = FALSE;
57 else
58 Stream_Free(tracker->currentPacket, TRUE);
59 }
60
61 if (create)
62 tracker->currentPacket = Stream_New(nullptr, 10ULL * 1024ULL);
63 if (!tracker->currentPacket)
64 return FALSE;
65 Stream_ResetPosition(tracker->currentPacket);
66 return TRUE;
67}
68
69ChannelStateTracker* channelTracker_new(pServerStaticChannelContext* channel,
70 ChannelTrackerPeekFn fn, void* data)
71{
72 ChannelStateTracker* ret = calloc(1, sizeof(ChannelStateTracker));
73 if (!ret)
74 return ret;
75
76 WINPR_ASSERT(fn);
77
78 ret->channel = channel;
79 ret->peekFn = fn;
80
81 if (!channelTracker_setCustomData(ret, data))
82 goto fail;
83
84 if (!channelTracker_resetCurrentPacket(ret))
85 goto fail;
86
87 return ret;
88
89fail:
90 WINPR_PRAGMA_DIAG_PUSH
91 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
92 channelTracker_free(ret);
93 WINPR_PRAGMA_DIAG_POP
94 return nullptr;
95}
96
97PfChannelResult channelTracker_update(ChannelStateTracker* tracker, const BYTE* xdata, size_t xsize,
98 UINT32 flags, size_t totalSize)
99{
100 PfChannelResult result = PF_CHANNEL_RESULT_ERROR;
101 BOOL firstPacket = (flags & CHANNEL_FLAG_FIRST) != 0;
102 BOOL lastPacket = (flags & CHANNEL_FLAG_LAST) != 0;
103
104 WINPR_ASSERT(tracker);
105
106 WLog_VRB(TAG, "channelTracker_update(%s): sz=%" PRIuz " first=%d last=%d",
107 tracker->channel->channel_name, xsize, firstPacket, lastPacket);
108 if (flags & CHANNEL_FLAG_FIRST)
109 {
110 if (!channelTracker_resetCurrentPacket(tracker))
111 return PF_CHANNEL_RESULT_ERROR;
112 channelTracker_setCurrentPacketSize(tracker, totalSize);
113 tracker->currentPacketReceived = 0;
114 tracker->currentPacketFragments = 0;
115 }
116
117 {
118 const size_t currentPacketSize = channelTracker_getCurrentPacketSize(tracker);
119 if (tracker->currentPacketReceived + xsize > currentPacketSize)
120 WLog_INFO(TAG, "cumulated size is bigger (%" PRIuz ") than total size (%" PRIuz ")",
121 tracker->currentPacketReceived + xsize, currentPacketSize);
122 }
123
124 tracker->currentPacketReceived += xsize;
125 tracker->currentPacketFragments++;
126
127 switch (channelTracker_getMode(tracker))
128 {
129 case CHANNEL_TRACKER_PEEK:
130 {
131 wStream* currentPacket = channelTracker_getCurrentPacket(tracker);
132 if (!Stream_EnsureRemainingCapacity(currentPacket, xsize))
133 return PF_CHANNEL_RESULT_ERROR;
134
135 Stream_Write(currentPacket, xdata, xsize);
136
137 WINPR_ASSERT(tracker->peekFn);
138 result = tracker->peekFn(tracker, firstPacket, lastPacket);
139 }
140 break;
141 case CHANNEL_TRACKER_PASS:
142 result = PF_CHANNEL_RESULT_PASS;
143 break;
144 case CHANNEL_TRACKER_DROP:
145 result = PF_CHANNEL_RESULT_DROP;
146 break;
147 default:
148 break;
149 }
150
151 if (lastPacket)
152 {
153 const size_t currentPacketSize = channelTracker_getCurrentPacketSize(tracker);
154 channelTracker_setMode(tracker, CHANNEL_TRACKER_PEEK);
155
156 if (tracker->currentPacketReceived != currentPacketSize)
157 WLog_INFO(TAG, "cumulated size(%" PRIuz ") does not match total size (%" PRIuz ")",
158 tracker->currentPacketReceived, currentPacketSize);
159 }
160
161 return result;
162}
163
164void channelTracker_free(ChannelStateTracker* t)
165{
166 if (!t)
167 return;
168
169 Stream_Free(t->currentPacket, TRUE);
170 free(t);
171}
172
179PfChannelResult channelTracker_flushCurrent(ChannelStateTracker* t, BOOL first, BOOL last,
180 BOOL toBack)
181{
182 UINT32 flags = CHANNEL_FLAG_FIRST;
183 BOOL r = 0;
184 const char* direction = toBack ? "F->B" : "B->F";
185 const size_t currentPacketSize = channelTracker_getCurrentPacketSize(t);
186 wStream* currentPacket = channelTracker_getCurrentPacket(t);
187
188 WINPR_ASSERT(t);
189
190 WLog_VRB(TAG, "channelTracker_flushCurrent(%s): %s sz=%" PRIuz " first=%d last=%d",
191 t->channel->channel_name, direction, Stream_GetPosition(currentPacket), first, last);
192
193 if (first)
194 return PF_CHANNEL_RESULT_PASS;
195
196 proxyData* pdata = t->pdata;
197 pServerStaticChannelContext* channel = t->channel;
198 if (last)
199 flags |= CHANNEL_FLAG_LAST;
200
201 if (toBack)
202 {
203 proxyChannelDataEventInfo ev = WINPR_C_ARRAY_INIT;
204
205 ev.channel_id = WINPR_ASSERTING_INT_CAST(UINT16, channel->front_channel_id);
206 ev.channel_name = channel->channel_name;
207 ev.data = Stream_Buffer(currentPacket);
208 ev.data_len = Stream_GetPosition(currentPacket);
209 ev.flags = flags;
210 ev.total_size = currentPacketSize;
211
212 pClientContext* pc = proxy_data_get_client_context(pdata);
213 if (!pc->sendChannelData)
214 return PF_CHANNEL_RESULT_ERROR;
215
216 return pc->sendChannelData(pc, &ev) ? PF_CHANNEL_RESULT_DROP : PF_CHANNEL_RESULT_ERROR;
217 }
218
219 pServerContext* ps = proxy_data_get_server_context(pdata);
220 r = ps->context.peer->SendChannelPacket(
221 ps->context.peer, WINPR_ASSERTING_INT_CAST(UINT16, channel->front_channel_id),
222 currentPacketSize, flags, Stream_Buffer(currentPacket), Stream_GetPosition(currentPacket));
223
224 return r ? PF_CHANNEL_RESULT_DROP : PF_CHANNEL_RESULT_ERROR;
225}
226
227WINPR_ATTR_NODISCARD
228static PfChannelResult pf_channel_generic_back_data(proxyData* pdata,
229 const pServerStaticChannelContext* channel,
230 const BYTE* xdata, size_t xsize, UINT32 flags,
231 size_t totalSize)
232{
233 proxyChannelDataEventInfo ev = WINPR_C_ARRAY_INIT;
234
235 WINPR_ASSERT(pdata);
236 WINPR_ASSERT(channel);
237
238 switch (channel->channelMode)
239 {
240 case PF_UTILS_CHANNEL_PASSTHROUGH:
241 ev.channel_id = WINPR_ASSERTING_INT_CAST(UINT16, channel->back_channel_id);
242 ev.channel_name = channel->channel_name;
243 ev.data = xdata;
244 ev.data_len = xsize;
245 ev.flags = flags;
246 ev.total_size = totalSize;
247
248 if (!pf_modules_run_filter(pdata->module, FILTER_TYPE_CLIENT_PASSTHROUGH_CHANNEL_DATA,
249 pdata, &ev))
250 return PF_CHANNEL_RESULT_DROP; /* Silently drop */
251
252 return PF_CHANNEL_RESULT_PASS;
253
254 case PF_UTILS_CHANNEL_INTERCEPT:
255 /* TODO */
256 case PF_UTILS_CHANNEL_BLOCK:
257 default:
258 return PF_CHANNEL_RESULT_DROP;
259 }
260}
261
262WINPR_ATTR_NODISCARD
263static PfChannelResult pf_channel_generic_front_data(proxyData* pdata,
264 const pServerStaticChannelContext* channel,
265 const BYTE* xdata, size_t xsize, UINT32 flags,
266 size_t totalSize)
267{
268 proxyChannelDataEventInfo ev = WINPR_C_ARRAY_INIT;
269
270 WINPR_ASSERT(pdata);
271 WINPR_ASSERT(channel);
272
273 switch (channel->channelMode)
274 {
275 case PF_UTILS_CHANNEL_PASSTHROUGH:
276 ev.channel_id = WINPR_ASSERTING_INT_CAST(UINT16, channel->front_channel_id);
277 ev.channel_name = channel->channel_name;
278 ev.data = xdata;
279 ev.data_len = xsize;
280 ev.flags = flags;
281 ev.total_size = totalSize;
282
283 if (!pf_modules_run_filter(pdata->module, FILTER_TYPE_SERVER_PASSTHROUGH_CHANNEL_DATA,
284 pdata, &ev))
285 return PF_CHANNEL_RESULT_DROP; /* Silently drop */
286
287 return PF_CHANNEL_RESULT_PASS;
288
289 case PF_UTILS_CHANNEL_INTERCEPT:
290 /* TODO */
291 case PF_UTILS_CHANNEL_BLOCK:
292 default:
293 return PF_CHANNEL_RESULT_DROP;
294 }
295}
296
297BOOL pf_channel_setup_generic(pServerStaticChannelContext* channel)
298{
299 WINPR_ASSERT(channel);
300 channel->onBackData = pf_channel_generic_back_data;
301 channel->onFrontData = pf_channel_generic_front_data;
302 return TRUE;
303}
304
305BOOL channelTracker_setMode(ChannelStateTracker* tracker, ChannelTrackerMode mode)
306{
307 WINPR_ASSERT(tracker);
308 tracker->mode = mode;
309 return TRUE;
310}
311
312ChannelTrackerMode channelTracker_getMode(ChannelStateTracker* tracker)
313{
314 WINPR_ASSERT(tracker);
315 return tracker->mode;
316}
317
318BOOL channelTracker_setPData(ChannelStateTracker* tracker, proxyData* pdata)
319{
320 WINPR_ASSERT(tracker);
321 tracker->pdata = pdata;
322 return TRUE;
323}
324
325proxyData* channelTracker_getPData(ChannelStateTracker* tracker)
326{
327 WINPR_ASSERT(tracker);
328 return tracker->pdata;
329}
330
331wStream* channelTracker_getCurrentPacket(ChannelStateTracker* tracker)
332{
333 WINPR_ASSERT(tracker);
334 return tracker->currentPacket;
335}
336
337BOOL channelTracker_setCustomData(ChannelStateTracker* tracker, void* data)
338{
339 WINPR_ASSERT(tracker);
340 tracker->trackerData = data;
341 return TRUE;
342}
343
344void* channelTracker_getCustomData(ChannelStateTracker* tracker)
345{
346 WINPR_ASSERT(tracker);
347 return tracker->trackerData;
348}
349
350size_t channelTracker_getCurrentPacketSize(ChannelStateTracker* tracker)
351{
352 WINPR_ASSERT(tracker);
353 return tracker->currentPacketSize;
354}
355
356BOOL channelTracker_setCurrentPacketSize(ChannelStateTracker* tracker, size_t size)
357{
358 WINPR_ASSERT(tracker);
359 tracker->currentPacketSize = size;
360 return TRUE;
361}