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