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