FreeRDP
Loading...
Searching...
No Matches
PacketMessage.c
1
22#include <winpr/config.h>
23
24#include "wlog.h"
25
26#include "PacketMessage.h"
27
28#include <winpr/wtypes.h>
29#include <winpr/crt.h>
30#include <winpr/file.h>
31#include <winpr/stream.h>
32#include <winpr/sysinfo.h>
33
34static BOOL Pcap_Read_Header(wPcap* pcap, wPcapHeader* header)
35{
36 return (pcap && pcap->fp && fread((void*)header, sizeof(wPcapHeader), 1, pcap->fp) == 1);
37}
38
39static BOOL Pcap_Write_Header(wPcap* pcap, wPcapHeader* header)
40{
41 return (pcap && pcap->fp && fwrite((void*)header, sizeof(wPcapHeader), 1, pcap->fp) == 1);
42}
43
44static BOOL Pcap_Write_RecordHeader(wPcap* pcap, wPcapRecordHeader* record)
45{
46 return (pcap && pcap->fp && fwrite((void*)record, sizeof(wPcapRecordHeader), 1, pcap->fp) == 1);
47}
48
49static BOOL Pcap_Write_RecordContent(wPcap* pcap, wPcapRecord* record)
50{
51 return (pcap && pcap->fp && fwrite(record->data, record->length, 1, pcap->fp) == 1);
52}
53
54static BOOL Pcap_Write_Record(wPcap* pcap, wPcapRecord* record)
55{
56 return Pcap_Write_RecordHeader(pcap, &record->header) && Pcap_Write_RecordContent(pcap, record);
57}
58
59wPcap* Pcap_Open(char* name, BOOL write)
60{
61 if (!name)
62 return nullptr;
63
64 wPcap* pcap = (wPcap*)calloc(1, sizeof(wPcap));
65
66 if (!pcap)
67 goto out_fail;
68
69 pcap->fp = winpr_fopen(name, write ? "w+b" : "rb");
70
71 if (!pcap->fp)
72 goto out_fail;
73
74 pcap->name = name;
75 pcap->write = write;
76 pcap->record_count = 0;
77
78 if (write)
79 {
80 pcap->header.magic_number = PCAP_MAGIC_NUMBER;
81 pcap->header.version_major = 2;
82 pcap->header.version_minor = 4;
83 pcap->header.thiszone = 0;
84 pcap->header.sigfigs = 0;
85 pcap->header.snaplen = 0xFFFFFFFF;
86 pcap->header.network = 1; /* ethernet */
87 if (!Pcap_Write_Header(pcap, &pcap->header))
88 goto out_fail;
89 }
90 else
91 {
92 if (_fseeki64(pcap->fp, 0, SEEK_END) < 0)
93 goto out_fail;
94 pcap->file_size = (SSIZE_T)_ftelli64(pcap->fp);
95 if (pcap->file_size < 0)
96 goto out_fail;
97 if (_fseeki64(pcap->fp, 0, SEEK_SET) < 0)
98 goto out_fail;
99 if (!Pcap_Read_Header(pcap, &pcap->header))
100 goto out_fail;
101 }
102
103 return pcap;
104
105out_fail:
106 Pcap_Close(pcap);
107 return nullptr;
108}
109
110void Pcap_Flush(wPcap* pcap)
111{
112 if (!pcap || !pcap->fp)
113 return;
114
115 while (pcap->record)
116 {
117 if (!Pcap_Write_Record(pcap, pcap->record))
118 return;
119 pcap->record = pcap->record->next;
120 }
121
122 (void)fflush(pcap->fp);
123}
124
125void Pcap_Close(wPcap* pcap)
126{
127 if (!pcap)
128 return;
129
130 Pcap_Flush(pcap);
131 if (pcap->fp)
132 (void)fclose(pcap->fp);
133 free(pcap);
134}
135
136static BOOL WLog_PacketMessage_Write_EthernetHeader(wPcap* pcap, wEthernetHeader* ethernet)
137{
138 wStream* s = nullptr;
139 wStream sbuffer = WINPR_C_ARRAY_INIT;
140 BYTE buffer[14] = WINPR_C_ARRAY_INIT;
141 BOOL ret = TRUE;
142
143 if (!pcap || !pcap->fp || !ethernet)
144 return FALSE;
145
146 s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer));
147 if (!s)
148 return FALSE;
149 Stream_Write(s, ethernet->Destination, 6);
150 Stream_Write(s, ethernet->Source, 6);
151 Stream_Write_UINT16_BE(s, ethernet->Type);
152 if (fwrite(buffer, sizeof(buffer), 1, pcap->fp) != 1)
153 ret = FALSE;
154
155 return ret;
156}
157
158static UINT16 IPv4Checksum(const BYTE* ipv4, int length)
159{
160 long checksum = 0;
161
162 while (length > 1)
163 {
164 const UINT16 tmp16 = *((const UINT16*)ipv4);
165 checksum += tmp16;
166 length -= 2;
167 ipv4 += 2;
168 }
169
170 if (length > 0)
171 checksum += *ipv4;
172
173 while (checksum >> 16)
174 checksum = (checksum & 0xFFFF) + (checksum >> 16);
175
176 return (UINT16)(~checksum);
177}
178
179static BOOL WLog_PacketMessage_Write_IPv4Header(wPcap* pcap, wIPv4Header* ipv4)
180{
181 wStream* s = nullptr;
182 wStream sbuffer = WINPR_C_ARRAY_INIT;
183 BYTE buffer[20] = WINPR_C_ARRAY_INIT;
184 int ret = TRUE;
185
186 if (!pcap || !pcap->fp || !ipv4)
187 return FALSE;
188
189 s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer));
190 if (!s)
191 return FALSE;
192 Stream_Write_UINT8(s, (BYTE)((ipv4->Version << 4) | ipv4->InternetHeaderLength));
193 Stream_Write_UINT8(s, ipv4->TypeOfService);
194 Stream_Write_UINT16_BE(s, ipv4->TotalLength);
195 Stream_Write_UINT16_BE(s, ipv4->Identification);
196 Stream_Write_UINT16_BE(s, (UINT16)((ipv4->InternetProtocolFlags << 13) | ipv4->FragmentOffset));
197 Stream_Write_UINT8(s, ipv4->TimeToLive);
198 Stream_Write_UINT8(s, ipv4->Protocol);
199 Stream_Write_UINT16(s, ipv4->HeaderChecksum);
200 Stream_Write_UINT32_BE(s, ipv4->SourceAddress);
201 Stream_Write_UINT32_BE(s, ipv4->DestinationAddress);
202 ipv4->HeaderChecksum = IPv4Checksum((BYTE*)buffer, 20);
203 Stream_Rewind(s, 10);
204 Stream_Write_UINT16(s, ipv4->HeaderChecksum);
205
206 if (fwrite(buffer, sizeof(buffer), 1, pcap->fp) != 1)
207 ret = FALSE;
208
209 return ret;
210}
211
212static BOOL WLog_PacketMessage_Write_TcpHeader(wPcap* pcap, wTcpHeader* tcp)
213{
214 wStream* s = nullptr;
215 wStream sbuffer = WINPR_C_ARRAY_INIT;
216 BYTE buffer[20] = WINPR_C_ARRAY_INIT;
217 BOOL ret = TRUE;
218
219 if (!pcap || !pcap->fp || !tcp)
220 return FALSE;
221
222 s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer));
223 if (!s)
224 return FALSE;
225 Stream_Write_UINT16_BE(s, tcp->SourcePort);
226 Stream_Write_UINT16_BE(s, tcp->DestinationPort);
227 Stream_Write_UINT32_BE(s, tcp->SequenceNumber);
228 Stream_Write_UINT32_BE(s, tcp->AcknowledgementNumber);
229 Stream_Write_UINT8(s, (UINT8)((tcp->Offset << 4) | (tcp->Reserved & 0xF)));
230 Stream_Write_UINT8(s, tcp->TcpFlags);
231 Stream_Write_UINT16_BE(s, tcp->Window);
232 Stream_Write_UINT16_BE(s, tcp->Checksum);
233 Stream_Write_UINT16_BE(s, tcp->UrgentPointer);
234
235 if (pcap->fp)
236 {
237 if (fwrite(buffer, sizeof(buffer), 1, pcap->fp) != 1)
238 ret = FALSE;
239 }
240
241 return ret;
242}
243
244static UINT32 g_InboundSequenceNumber = 0;
245static UINT32 g_OutboundSequenceNumber = 0;
246
247BOOL WLog_PacketMessage_Write(wPcap* pcap, void* data, size_t length, DWORD flags)
248{
249 wTcpHeader tcp;
250 wIPv4Header ipv4;
251 wPcapRecord record;
252 wEthernetHeader ethernet;
253 ethernet.Type = 0x0800;
254
255 if (!pcap || !pcap->fp)
256 return FALSE;
257
258 if (flags & WLOG_PACKET_OUTBOUND)
259 {
260 /* 00:15:5D:01:64:04 */
261 ethernet.Source[0] = 0x00;
262 ethernet.Source[1] = 0x15;
263 ethernet.Source[2] = 0x5D;
264 ethernet.Source[3] = 0x01;
265 ethernet.Source[4] = 0x64;
266 ethernet.Source[5] = 0x04;
267 /* 00:15:5D:01:64:01 */
268 ethernet.Destination[0] = 0x00;
269 ethernet.Destination[1] = 0x15;
270 ethernet.Destination[2] = 0x5D;
271 ethernet.Destination[3] = 0x01;
272 ethernet.Destination[4] = 0x64;
273 ethernet.Destination[5] = 0x01;
274 }
275 else
276 {
277 /* 00:15:5D:01:64:01 */
278 ethernet.Source[0] = 0x00;
279 ethernet.Source[1] = 0x15;
280 ethernet.Source[2] = 0x5D;
281 ethernet.Source[3] = 0x01;
282 ethernet.Source[4] = 0x64;
283 ethernet.Source[5] = 0x01;
284 /* 00:15:5D:01:64:04 */
285 ethernet.Destination[0] = 0x00;
286 ethernet.Destination[1] = 0x15;
287 ethernet.Destination[2] = 0x5D;
288 ethernet.Destination[3] = 0x01;
289 ethernet.Destination[4] = 0x64;
290 ethernet.Destination[5] = 0x04;
291 }
292
293 ipv4.Version = 4;
294 ipv4.InternetHeaderLength = 5;
295 ipv4.TypeOfService = 0;
296 ipv4.TotalLength = (UINT16)(length + 20 + 20);
297 ipv4.Identification = 0;
298 ipv4.InternetProtocolFlags = 0x02;
299 ipv4.FragmentOffset = 0;
300 ipv4.TimeToLive = 128;
301 ipv4.Protocol = 6; /* TCP */
302 ipv4.HeaderChecksum = 0;
303
304 if (flags & WLOG_PACKET_OUTBOUND)
305 {
306 ipv4.SourceAddress = 0xC0A80196; /* 192.168.1.150 */
307 ipv4.DestinationAddress = 0x4A7D64C8; /* 74.125.100.200 */
308 }
309 else
310 {
311 ipv4.SourceAddress = 0x4A7D64C8; /* 74.125.100.200 */
312 ipv4.DestinationAddress = 0xC0A80196; /* 192.168.1.150 */
313 }
314
315 tcp.SourcePort = 3389;
316 tcp.DestinationPort = 3389;
317
318 if (flags & WLOG_PACKET_OUTBOUND)
319 {
320 tcp.SequenceNumber = g_OutboundSequenceNumber;
321 tcp.AcknowledgementNumber = g_InboundSequenceNumber;
322 WINPR_ASSERT(length + g_OutboundSequenceNumber <= UINT32_MAX);
323 g_OutboundSequenceNumber += WINPR_ASSERTING_INT_CAST(uint32_t, length);
324 }
325 else
326 {
327 tcp.SequenceNumber = g_InboundSequenceNumber;
328 tcp.AcknowledgementNumber = g_OutboundSequenceNumber;
329
330 WINPR_ASSERT(length + g_InboundSequenceNumber <= UINT32_MAX);
331 g_InboundSequenceNumber += WINPR_ASSERTING_INT_CAST(uint32_t, length);
332 }
333
334 tcp.Offset = 5;
335 tcp.Reserved = 0;
336 tcp.TcpFlags = 0x0018;
337 tcp.Window = 0x7FFF;
338 tcp.Checksum = 0;
339 tcp.UrgentPointer = 0;
340 record.data = data;
341 record.length = length;
342 const size_t offset = 14 + 20 + 20;
343 WINPR_ASSERT(record.length <= UINT32_MAX - offset);
344 const uint32_t rloff = WINPR_ASSERTING_INT_CAST(uint32_t, record.length + offset);
345 record.header.incl_len = rloff;
346 record.header.orig_len = rloff;
347 record.next = nullptr;
348
349 UINT64 ns = winpr_GetUnixTimeNS();
350 record.header.ts_sec = (UINT32)WINPR_TIME_NS_TO_S(ns);
351 record.header.ts_usec = WINPR_TIME_NS_REM_US(ns);
352
353 if (!Pcap_Write_RecordHeader(pcap, &record.header) ||
354 !WLog_PacketMessage_Write_EthernetHeader(pcap, &ethernet) ||
355 !WLog_PacketMessage_Write_IPv4Header(pcap, &ipv4) ||
356 !WLog_PacketMessage_Write_TcpHeader(pcap, &tcp) || !Pcap_Write_RecordContent(pcap, &record))
357 return FALSE;
358 (void)fflush(pcap->fp);
359 return TRUE;
360}